UVa 1627 - Team them up!——[0-1背包]
Your task is to divide a number of persons into two teams, in such a way, that:
- everyone belongs to one of the teams;
- every team has at least one member;
- every person in the team knows every other person in his team;
- teams are as close in their sizes as possible.
This task may have many solutions. You are to find and output any solution, or to report that the solution does not exist.
Input
The input begins with a single positive integer on a line by itself indicating the number of the cases following, each of them as described below. This line is followed by a blank line, and there is also a blank line between two consecutive inputs.
For simplicity, all persons are assigned a unique integer identifier from 1 to N.
The first line in the input file contains a single integer number N (2 ≤ N ≤ 100) - the total number of persons to divide into teams, followed by N lines - one line per person in ascending order of their identifiers. Each line contains the list of distinct numbers Aij (1 ≤ Aij ≤ N, Aij ≠ i) separated by spaces. The list represents identifiers of persons that ith person knows. The list is terminated by 0.
Output
For each test case, the output must follow the description below. The outputs of two consecutive cases will be separated by a blank line.
If the solution to the problem does not exist, then write a single message "No solution" (without quotes) to the output file. Otherwise write a solution on two lines. On the first line of the output file write the number of persons in the first team, followed by the identifiers of persons in the first team, placing one space before each identifier. On the second line describe the second team in the same way. You may write teams and identifiers of persons in a team in any order.
Sample Input
2 5
3 4 5 0
1 3 5 0
2 1 4 5 0
2 3 5 0
1 2 3 4 0 5
2 3 5 0
1 4 5 3 0
1 2 5 0
1 2 3 0
4 3 2 1 0
Sample Output
No solution 3 1 3 5
2 2 4 题意分析:
以“不相互认识关系”建无向图,每个连通块都可以分成两队,如果存在已经分成一队的两个人互相不认识,说明无解,表现在图中就是存在环,用bfs求连通块即可。
将每个连通块中必须分到不同队的两组人分别记录下来team0,team1,接下来对求出的各个连通块动态规划,两队人数之差 dt=team0-team1,则要选择将每个连通块适当分组使dt最接近0。
以d(i,j)表示已经选择前i个连通块,且dt=j时的最优解。
状态转移方程为 d(i,j)=min{d(i-1,j-dt[i])+dt[i],d(i-1,j+dt[i]-dt[i])},其中dt[i]是指第i个连通块的两队人数差。
用b(i,j)记录当前状态应该分组的方式,0表示将连通块的team0部分分到0组,1则表示将team0部分分到1组。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=;
#define INF 100000000
int know[maxn][maxn];
int unknow[maxn][maxn];
int team[maxn];
int n;
vector<int> block[maxn][];
int num;
int d[maxn][*maxn];
int b[maxn][*maxn];
bool dfs(int i,int t,vector<int> *b){
team[i]=t;
b[t].push_back(i);
bool ok=true;
for(int j=;j<=n;j++){
if(unknow[i][j]){
if(team[j]==-) {
if(!dfs(j,!t,b)){
ok=false;
break;
}
}
else if(team[j]!=t) continue;
else{
ok=false;
break;
}
}
}
return ok;
}
bool blocks(){
for(int i=;i<maxn;i++)
for(int j=;j<;j++)
block[i][j].clear();
num=;
for(int i=;i<=n;i++)
if(team[i]==-)
if(!dfs(i,,block[num++]))
return false;
return true;
}
void dp(){
memset(d, , sizeof d);
memset(b,,sizeof b);
for(int i=;i<=num;i++){
for(int j=;j<*maxn;j++){
if(i==){
d[i][j]=INF;
if(j==maxn)
d[i][j]=;
continue;
}
d[i][j]=INF;
int deta=block[i-][].size()-block[i-][].size();
if(j-deta>=&&j-deta<*maxn&&d[i-][j-deta]!=INF){
if(abs(d[i][j])>abs(d[i-][j-deta]+deta)){
d[i][j]=d[i-][j-deta]+deta;
b[i][j]=;
}
}
if(j+deta>=&&j+deta<*maxn&&d[i-][j+deta]!=INF){
if(abs(d[i][j])>abs(d[i-][j+deta]-deta)){
d[i][j]=d[i-][j+deta]-deta;
b[i][j]=;
}
} }
}
}
void print(){
int ans=INF,p=;
for(int k=;k<*maxn;k++){
if(abs(ans)>abs(d[num][k])){
ans=d[num][k];
p=k;
}
}
vector<int> team[];
for(int i=num,j=p;i>=;i--){
int dt=block[i-][].size()-block[i-][].size();
int t=b[i][j];
if(t==){
for(int k=;k<block[i-][].size();k++)
team[].push_back(block[i-][][k]);
for(int k=;k<block[i-][].size();k++)
team[].push_back(block[i-][][k]);
j-=dt;
}
else{
for(int k=;k<block[i-][].size();k++)
team[].push_back(block[i-][][k]);
for(int k=;k<block[i-][].size();k++)
team[].push_back(block[i-][][k]);
j+=dt;
}
}
printf("%d",int(team[].size()));
for(int i=;i<team[].size();i++){
printf(" %d",team[][i]);
}
printf("\n");
printf("%d",int(team[].size()));
for(int i=;i<team[].size();i++){
printf(" %d",team[][i]);
}
printf("\n");
}
int main(int argc, const char * argv[]) {
int tt;
scanf("%d",&tt);
int cas=;
while(tt--){
memset(know,,sizeof know);
memset(unknow,,sizeof know);
memset(team,-,sizeof team); scanf("%d",&n);
for(int i=;i<=n;i++){
int j;
while(scanf("%d",&j)&&j){
know[i][j]=;
}
} for(int j=;j<=n;j++){
for(int i=;i<=n;i++){
if(i==j)
continue;
if(!know[i][j]){
unknow[i][j]=unknow[j][i]=;
}
}
} if(!blocks()){
printf("No solution\n");
if(tt) printf("\n");
continue;
}
dp();
print();
if(tt) printf("\n");
} return ;
}
UVa 1627 - Team them up!——[0-1背包]的更多相关文章
- 【暑假】[深入动态规划]UVa 1627 Team them up!
UVa 1627 Team them up! 题目: Team them up! Time Limit: 3000MS Memory Limit: Unknown 64bit IO Forma ...
- UVa 1627 Team them up! (01背包+二分图)
题意:给n个分成两个组,保证每个组的人都相互认识,并且两组人数相差最少,给出一种方案. 析:首先我们可以知道如果某两个人不认识,那么他们肯定在不同的分组中,所以我们可以根据这个结论构造成一个图,如果两 ...
- UVA 1627 Team them up!
https://cn.vjudge.net/problem/UVA-1627 题目 有n(n≤100)个人,把他们分成非空的两组,使得每个人都被分到一组,且同组中的人相互认识.要求两组的成员人数尽量接 ...
- UVA.540 Team Queue (队列)
UVA.540 Team Queue (队列) 题意分析 有t个团队正在排队,每次来一个新人的时候,他可以插入到他最后一个队友的身后,如果没有他的队友,那么他只能插入到队伍的最后.题目中包含以下操作: ...
- poj1417 带权并查集+0/1背包
题意:有一个岛上住着一些神和魔,并且已知神和魔的数量,现在已知神总是说真话,魔总是说假话,有 n 个询问,问某个神或魔(身份未知),问题是问某个是神还是魔,根据他们的回答,问是否能够确定哪些是神哪些是 ...
- C:\Windows\system32\config\systemprofile\AppData\Local\Microsoft\Team Foundation\4.0\Cache\VersionControl.config is not valid and cannot be loaded.
Recently, we experienced a strange problem with TFS 2010. We spent a few days before we figured it o ...
- P1417 烹调方案 (0/1背包+贪心)
题目背景 由于你的帮助,火星只遭受了最小的损失.但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星.不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~ gw还是会做饭的,于是拿出了储藏的 ...
- 洛谷 P1064 金明的预算方案 (有依赖的0/1背包)
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NN元钱就行”. ...
- POJ 1636 Prison rearrangement DFS+0/1背包
题目链接: id=1636">POJ 1636 Prison rearrangement Prison rearrangement Time Limit: 3000MS Memor ...
随机推荐
- 【转】基于OLSR路由协议实现Ad-Hoc组网
一.软件包的安装 1. olsrd软件包的安装 libpthread_0.9.33.2-1_ar71xx.ipk olsrd_0.6.6.2-4_ar71xx.ipk 2. luci的安装 olsrd ...
- Dubbo报org.I0Itec.zkclient.exception.ZkNoNodeException异常
解决办法就是添加zkclient的jar,maven工程的话增加如下引用: <dependency> <groupId>com.github.sgroschupf< ...
- iOS 微信支付如果遇到跳转只有一个确定请看这里
http://www.cocoachina.com/bbs/read.php?tid-321546.html 今天在联调微信支付,不得不说,和它比起来,阿里的支付sdk真的是太好用了.果然和后端同学在 ...
- Leetcode784.Letter Case Permutation字母大小写全排列
给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串.返回所有可能得到的字符串集合. 示例: 输入: S = "a1b2" 输出: ["a1 ...
- Servlet FilterConfig
FilterConfig的对象由Web容器创建.这个对象可用于获取web.xml文件中Filter的配置信息 文件:index.html <!DOCTYPE html> <html& ...
- 洛谷 P2568 GCD(莫比乌斯反演)
题意:$\sum_{i=1}^{n}\sum_{j=1}^{n}[gcd(i,j)\epsilon prime]$. 对于这类题一般就是枚举gcd,可得: =$\sum_{d\epsilon prim ...
- pycahrm安装说明
从官网下载http://www.jetbrains.com/pycharm/download/other.html(PS:现在需要翻墙可以直接用文件夹里的那个) 下载完成后双击文件 第二步:双击已下载 ...
- 使用 Linux Centos Docker 安装 2Bizbix
在 Docker 安装 2Bizbix 安装 Centos 7 安装 mysql5.5 镜像 映射好数据库的配置文件和数据库目录 在 Windows 安装 2Bizbox 安装 jboss/base- ...
- HZOJ 太阳神
所以我刚学反演还没学反演就要做这么一道神仙题…… 首先大于n不好求,补集转化. $ans=n*n-\sum \limits _{i=1}^{n} \sum \limits _{j=1}^{n} \le ...
- AtCoder Regular Contest 082 D Derangement
AtCoder Regular Contest 082 D Derangement 与下标相同与下个交换就好了.... Define a sequence of ’o’ and ’x’ of lengt ...