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 ...
随机推荐
- python中几种单例模式的实现
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- Hashkell 第一篇
心情极差.................. 无事可做,其实是没心情去做事情,只好又翻起了haskell入门 记下几点,以备查询: 1. 函数名首字符是不可以大写的, 而且名称中可以有单引号,这也是合 ...
- 【Leetcode 堆、快速选择、Top-K问题 BFPRT】数组中的第K个最大元素(215)
这道题很强大,引出了很多知识点 题目 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5 ...
- jquery全屏图片滑动切换
在线演示 本地下载
- 总结 ESP8266 RTOS 开发环境搭建
总结 ESP8266 RTOS 开发环境搭建 仔细看官方文档. 必须一步一步操作. 不要想当然,以为 make 就可以. 忽略编译警告,除非是错误. 工具链必须使用官方提供的. 多看看 Issues ...
- 2018年DDoS攻击全态势:战胜第一波攻击成“抗D” 关键
2018年,阿里云安全团队监测到云上DDoS攻击发生近百万次,日均攻击2000余次.目前阿里云承载着中国40%网站,为全球上百万客户提供基础安全防御.可以说,阿里云上的攻防态势是整个中国攻防态势的缩影 ...
- scala2.11读取文件
1.读取行 要读取文件的所有行,可以调用scala.io.Source对象的getLines方法: import scala.io.Source val source = Source.fromFil ...
- Best Time to Sell and Buy Stock
这道题想了很多,但是想多了.这个题思路很简单,如果当前值大于最小值,就计算差,和最大利润值比较. class Solution { public: int maxProfit(vector<in ...
- 【Mysql的那些事】Django数据库配置
1:安装与配置 1:pip install PyMySQL(或者直接使用Pycharm的setting,点击添加PyMySQL) 2:在Django的工程同名子目录的__init__.py文件中添加如 ...
- POI解决内存溢出问题
在POI3.8中SXSSF仅仅支持excel2007格式是对XSSF的一种流的扩展.目的在生成excel时候,需要生成大量的数据的时候,通过刷新的方式将excel内存信息刷新到硬盘的方式,提供写入数据 ...