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 ...
随机推荐
- R是用于统计分析、绘图的语言和操作环境
R是一套完整的数据处理.计算和制图软件系统.其功能包括:数据存储和处理系统:数组运算工具(其向量.矩阵运算方面功能尤其强大):完整连贯的统计分析工具:优秀的统计制图功能:简便而强大的编程语言:可操纵数 ...
- shops
#!/usr/bin/env python #coding:utf- import urllib2,sys,re,os,string reload(sys); sys.setdefaultencodi ...
- poj2449第K短路问题(A*算法)
启发函数:f(x)=g(x)+h(x); g(x)表示初始点到x状态的代价,h(x)表示从x的状态到目标状态的代价的估计值(并不是真实的),实际最小代价<=h(x); 起点s,终点t,x.v=s ...
- oracle如何启用审计
通过数据库初始化参数文件中的AUDIT_TRAIL 初始化参数启用和禁用数据库审计. DB 启用数据库审计并引导所有审计记录到数据库的审计跟踪 OS 启用数据库审计并引导所有审计记录到操作系统的审 ...
- JavaScript--微博发布效果
效果图: 实现思路: 当发布按钮被点击时,又会分为三种情况 1.如果输入的内容为空,弹出提示:不能发布空微博 2.如果输入的文字超过120,弹出提示,微博内容不能超过120 3.正常发布微博到列表里 ...
- 简单利用XSS获取Cookie信息实例演示
简单利用XSS获取Cookie信息实例演示 首先要找到一个有XXS的站,这里就不整什么大站了,谷歌一下inurl:'Product.asp?BigClassName',搜出来的命中率也比较高.随便 ...
- sql —— check
CHECK 约束用于限制列中的值的范围. 原表: 现在要对性别这一列进行约束,只准值为男或者女. 步骤: 1. 2. 3. 4. 5. ctrl + s 保存一下, 现在不可以随意的修改性别了. 完成 ...
- python 并发之线程
一.什么是线程 #指的是一条流水线的工作过程,关键的一句话:一个进程内最少自带一个线程,其实进程根本不能执行,进程不是执行单位,是资源的单位,分配资源的单位 #线程才是执行单位 #进程:做手机屏幕的工 ...
- Java练习 SDUT-3848_Shift Dot
Shift Dot Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 给出平面直角坐标系中的一点,并顺序给出n个向量,求该 ...
- docker查看运行容器详细信息
使用docker ps命令可以查看所有正在运行中的容器列表, 使用docker inspect命令我们可以查看更详细的关于某一个容器的信息. $ docker inspect 容器id/image