【暑假】[深入动态规划]UVa 1627 Team them up!
UVa 1627 Team them up!
题目:
| Time Limit: 3000MS | Memory Limit: Unknown | 64bit IO Format: %lld & %llu |
Description
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 --------------------------------------------------------------------------------------------------------------------------------------------------------------------
思路:
给出关系图,不相识(互相)的两人必须分在不同组,要求分成两组且分组后有两组人数相差最少。
按照相反关系重新建图,如果两人不互相认识则连边,那么在一个联通块中,如何分组或是不能分组可知。如果不能构成二分图,那么问题无解因为不能满足必须分在不同组的要求。
设d[i][j+n]表示已经考虑到第i个联通块且两组相差i的情况是否存在。因为 j 属于[-n,n]所以需要+n调节j的范围。
有状态转移方程:
if(d[i][j+n])
d[i+1][j+n+diff[i]]=1;
d[i+1][j+n-diff[i]]=1;
其中diff[i]代表第i个联通块可分成的两组人数之差。
ans的得到需要按绝对值从小到大依此枚举,根据d[][]判断是否存在即可。
代码:
#include<cstdio>
#include<cstring>
#include<vector>
#define FOR(a,b,c) for(int a=(b);a<(c);a++)
using namespace std; const int maxn = + ; int colors_num,n,m;
int d[maxn][*maxn],diff[maxn];
int G[maxn][maxn];
vector<int> team[maxn][];
int colors[maxn]; //如果不是二部图return false
bool dfs(int u,int c) {
colors[u]=c; //c==1 || 2
team[colors_num][c-].push_back(u);
FOR(v,,n)
if(u!=v && !(G[u][v]&&G[v][u])){ //不互相认识
if(colors[v]> && colors[u]==colors[v]) return false;
//u v不能在一组却出现在了一组
if(!colors[v] && !dfs(v,-c)) return false;
}
return true;
} bool build_graph() {
colors_num=;
memset(colors,,sizeof(colors)); FOR(i,,n) if(!colors[i]){
team[colors_num][].clear();
team[colors_num][].clear();
if(!dfs(i,)) return false;
diff[colors_num]=team[colors_num][].size()-team[colors_num][].size();
colors_num++;
}
return true;
} void print(int ans) {
vector<int> team1, team2;
for(int i = colors_num-; i >= ; i--) { //对 每个联通块
int t;
if(d[i][ans-diff[i]+n]) { t = ; ans -= diff[i]; } //判断+- //组号为t
else { t = ; ans += diff[i]; }
for(int j = ; j < team[i][t].size(); j++) //加入team1
team1.push_back(team[i][t][j]);
for(int j = ; j < team[i][^t].size(); j++) //加入team2
team2.push_back(team[i][^t][j]);
}
printf("%d", team1.size());
for(int i = ; i < team1.size(); i++) printf(" %d", team1[i]+);
printf("\n"); printf("%d", team2.size());
for(int i = ; i < team2.size(); i++) printf(" %d", team2[i]+);
printf("\n");
} void dp() {
//d[i][j+n] 代表考虑到第i个联通块时两组相差j的情况是否存在
memset(d,,sizeof(d));
d[][+n]=; //+n 调节范围
FOR(i,,colors_num)
FOR(j,-n,n+) if(d[i][j+n]) {
//刷表 存在
d[i+][j+n+diff[i]]=;
d[i+][j+n-diff[i]]=;
} FOR(ans,,n+) {
if(d[colors_num][n+ans]) {print(ans); return; }
if(d[colors_num][n-ans]) {print(-ans); return; }
}
} int main() {
int T; scanf("%d",&T);
while(T--) {
scanf("%d",&n);
FOR(u,,n) { //读入原图
int v;
while(scanf("%d",&v) && v) G[u][v-]=; //v-1调节序号
}
if(n== || !build_graph()) printf("No solution\n"); //n==1 -> no solution
else dp(); if(T) printf("\n");
}
return ;
}
【暑假】[深入动态规划]UVa 1627 Team them up!的更多相关文章
- 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 ...
- UVA 1627 Team them up!
https://cn.vjudge.net/problem/UVA-1627 题目 有n(n≤100)个人,把他们分成非空的两组,使得每个人都被分到一组,且同组中的人相互认识.要求两组的成员人数尽量接 ...
- UVa 1627 Team them up! (01背包+二分图)
题意:给n个分成两个组,保证每个组的人都相互认识,并且两组人数相差最少,给出一种方案. 析:首先我们可以知道如果某两个人不认识,那么他们肯定在不同的分组中,所以我们可以根据这个结论构造成一个图,如果两 ...
- UVA.540 Team Queue (队列)
UVA.540 Team Queue (队列) 题意分析 有t个团队正在排队,每次来一个新人的时候,他可以插入到他最后一个队友的身后,如果没有他的队友,那么他只能插入到队伍的最后.题目中包含以下操作: ...
- 【暑假】[深入动态规划]UVa 1628 Pizza Delivery
UVa 1628 Pizza Delivery 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=51189 思路: ...
- 【暑假】[深入动态规划]UVa 1380 A Scheduling Problem
UVa 1380 A Scheduling Problem 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=41557 ...
- 【暑假】[深入动态规划]UVa 12170 Easy Climb
UVa 12170 Easy Climb 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=24844 思路: 引别人一 ...
- 【暑假】[深入动态规划]UVa 10618 The Bookcase
UVa 12099 The Bookcase 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=42067 思路: ...
- 【暑假】[深入动态规划]UVa 10618 Fun Game
UVa 10618 Fun Game 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=36035 思路: 一圈人围坐 ...
随机推荐
- NOIP2014 行记
不知道OI是啥或者信息学竞赛是啥的可以按`Ctrl+W`. <del>很早开始写的..准备出分之后再发布.</del> 谨以此文纪念我信息学竞赛的第一次正式考试. 背景音乐底部 ...
- unity 3d 获取鼠标当前坐标
获取当前鼠标position:Input.mousePosition;
- Tiny6410 LED字符设备驱动
1.查看用户手册 led1.led2.led3.led4 连接的分别是 GPK4.GPK5.GPK6.GPK7 2.查询6410芯片手册 下面还需要3个步骤: 1.设置GPIO为OUTPUT. 将GP ...
- C++: std::string 与 Unicode 如何结合?
关键字:std::string Unicode 转自:http://www.vckbase.com/document/viewdoc/?id=1293 一旦知道 TCHAR 和_T 是如何工作的,那么 ...
- POJ2349+prim
最小生成树 /* prim 题意:给定一些点,一些卫星,一个卫星能连接两个点,点和点之间通信有一定的距离限制. 问能使得所有的点联通的最小距离. */ #include<stdio.h> ...
- [itint5]完全二叉树节点个数的统计
http://www.itint5.com/oj/#4 这题是利用完全二叉树的性质计算节点数目.那么是通过比较左右子树的最左结点的高度来看那边是满的,然后递归计算. //使用getLeftChildN ...
- Qt的版本历史
发展史 Qt的第一个商业版本于1995年推出,随后Qt的发展就很快了,下面是Qt发展史上的一 些里程碑,从之前的Qt1.x开始到现在的Qt5.x. Qt1-3 版本 发布日期 1.40 10 July ...
- Android:布局实例之常见用户设置界面
实现效果: 整理思路: 1.控件:文字TextView 和 右箭头ImageView 2.因为考虑到点击效果,设计为:最外层为全圆角,内层有四种情况,分别为上圆角.无圆角.下圆角和全圆角. 3.内层样 ...
- HBase Shell输入命令无法删除问题解决技巧
一.引言: HBase shell使用过程中,使用CRT客户端,命令输入后无法删除一直困绕着我,今天终于受不了,几番度娘,谷哥之后,终于有了解决方法,特共享给大家. 二.操作步骤 secureCRT中 ...
- 【剑指offer】找出数组中出现一次的两个数
2013-09-08 10:50:46 一个整型数组中,除了两个数字之外,其他数字都出现了2次,找出这两个只出现一次的数字,要求时间复杂度是O(N),空间复杂度是O(1). 小结: 任何数与0异或,结 ...