题目链接:

http://poj.org/problem?id=1112

题目大意:

有编号为1~n的n个人,给出每个人认识的人的编号,注意A认识B,B不一定认识A,让你将所有的人分成两组,要求每组的人相互认识,且两组的人数要尽可能的接近。

求出每组的人的编号。

解题思路:

图论+背包(输出物品)。

相互认识的关系不好确定分组,如果转换思路,考虑相互不认识的情况就简单好多,如果A不认识B,且B不认识C,那么A和C必须分到同一组里。所以就想到了,连通分量的染色,相邻的两个染不同的颜色(0或1),每一个连通分量分成两组,并且相同颜色的人不能有边(一定要相互认识),容易知道不同连通分量的人一定相互认识,否则是连通的。

然后问题就转化为有多个连通分量,每个连通分量有两组,每组必须属于一个队,求两个队的人数差最小,并分别输出两队的人。

dp[i][j]表示到了第i个连通分量,且第一个队的人数为j时是否能够恰好凑齐。

ans[i][j]表示对应于状态dp[i][j]时的选择,0表示选择0颜色的节点,1表示选择1颜色的节点。

求出dp[num][]后,根据ans[num][]的值往前推,颜色选好后把所有的该颜色节点都加进去该队里去。

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std; //本题关键是建反图,将相互认识的情况,转化成相互不认识的情况
//思维逆向,这样便于处理,因为不同的连通区一定相互认识,同一连通区内可以分层处理,相邻的一定不相互认识
#define Maxn 110
struct Node
{
int cnt[2];
int sa[2][Maxn]; //存每个连通区间的两类人数
}node[Maxn];
bool kn[Maxn][Maxn],nn[Maxn][Maxn];
bool vis[Maxn];
int n,num;
bool dp[Maxn][Maxn]; //dp[i]表示第一个team的人数
int ans[Maxn][Maxn]; //记录到达第i个连通区且状态为j时第一个队的选择
int aa[Maxn],bb[Maxn];//aa表示第一个队的组成成员, void dfs(int v,int p)
{
node[num].cnt[p]++; //该连通区该颜色的人数
node[num].sa[p][node[num].cnt[p]]=v;//标号
for(int i=1;i<=n;i++)
{
if(!nn[v][i]||vis[i])
continue;
vis[i]=true;
dfs(i,p^1);
}
} bool ok() //对每一个区间扫描是否有矛盾的
{
for(int i=1;i<=num;i++)
{
for(int p=0;p<2;p++)
{
for(int k=1;k<=node[i].cnt[p];k++)
for(int m=k+1;m<=node[i].cnt[p];m++)
{
int a=node[i].sa[p][k],b=node[i].sa[p][m];
if(nn[a][b]) //同一联通快内,同颜色不认识的话有矛盾
return false;
}
}
}
return true;
} int main()
{
int a; while(~scanf("%d",&n))
{
memset(kn,false,sizeof(kn));
memset(nn,false,sizeof(nn));
for(int i=1;i<=n;i++)
while(scanf("%d",&a)&&a)
kn[i][a]=true;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(!kn[i][j]||!kn[j][i])
nn[i][j]=nn[j][i]=true; //建无向反图
memset(vis,false,sizeof(vis));
num=0; //num表示连通区的个数
for(int i=1;i<=n;i++) //对每一个连通区间 染色
if(!vis[i])
{
num++;
vis[i]=true;
node[num].cnt[0]=node[num].cnt[1]=0;
dfs(i,0);
}
if(!ok())
{
printf("No solution\n");
continue;
}
memset(dp,false,sizeof(dp));
memset(ans,0,sizeof(ans));
dp[0][0]=true;
for(int i=1;i<=num;i++) //简单背包,每个连通分量每种颜色必须进一个小队
{
for(int j=n;j>=min(node[i].cnt[0],node[i].cnt[1]);j--) //第一个背包
{
if(!dp[i][j]&&j>=node[i].cnt[0]&&dp[i-1][j-node[i].cnt[0]])
dp[i][j]=true,ans[i][j]=0;
if(!dp[i][j]&&j>=node[i].cnt[1]&&dp[i-1][j-node[i].cnt[1]])
dp[i][j]=true,ans[i][j]=1;
}
}
int gap=n,temp1=0,temp2=0;
for(int i=1;i<=n;i++) //求出 差值最小的 两支队伍数
if(dp[num][i]&&abs(i-(n-i))<gap)
gap=abs(i-(n-i)),temp1=i;
temp2=n-temp1;
if(!temp1||!temp2)
printf("No solution\n");
else
{
//printf("%d %d\n",temp1,temp2);
int p=0,q=0;
for(int i=num;i>=1;i--)
{
//printf(":::%d\n",ans[i][temp1]);
if(ans[i][temp1]) //逆向输出,说明达到该状态第一队选择了第1种
{
for(int j=1;j<=node[i].cnt[1];j++)
aa[++p]=node[i].sa[1][j];
for(int j=1;j<=node[i].cnt[0];j++)
bb[++q]=node[i].sa[0][j];
temp1-=node[i].cnt[1]; //注意第一队要减去选择了的人数 每个连通分量必须有人选,
} //第一队选择了第0种
else
{
for(int j=1;j<=node[i].cnt[0];j++)
aa[++p]=node[i].sa[0][j];
for(int j=1;j<=node[i].cnt[1];j++)
bb[++q]=node[i].sa[1][j];
temp1-=node[i].cnt[0];
}
}
printf("%d",q);
for(int i=1;i<=q;i++)
printf(" %d",bb[i]);
putchar('\n');
printf("%d",p);
for(int i=1;i<=p;i++)
printf(" %d",aa[i]);
putchar('\n'); } }
return 0;
}

图论+dp poj 1112 Team Them Up!的更多相关文章

  1. POJ 1112 Team Them Up! 二分图判定+01背包

    题目链接: http://poj.org/problem?id=1112 Team Them Up! Time Limit: 1000MSMemory Limit: 10000K 问题描述 Your ...

  2. poj 2259 Team Queue

    Team Queue Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 2977   Accepted: 1092 Descri ...

  3. 【POJ 1112】Team Them Up!(二分图染色+DP)

    Description Your task is to divide a number of persons into two teams, in such a way, that: everyone ...

  4. 状压DP POJ 3254 Corn Fields

    题目传送门 /* 状态压缩DP:先处理硬性条件即不能种植的,然后处理左右不相邻的, 接着就是相邻两行查询所有可行的种数并累加 写错一个地方差错N久:) 详细解释:http://www.tuicool. ...

  5. 状压DP POJ 2411 Mondriaan'sDream

    题目传送门 /* 题意:一个h*w的矩阵(1<=h,w<=11),只能放1*2的模块,问完全覆盖的不同放发有多少种? 状态压缩DP第一道:dp[i][j] 代表第i行的j状态下的种数(状态 ...

  6. dp poj 1080 Human Gene Functions

    题目链接: http://poj.org/problem?id=1080 题目大意: 给两个由A.C.T.G四个字符组成的字符串,可以在两串中加入-,使得两串长度相等. 每两个字符匹配时都有个值,求怎 ...

  7. POJ 2259 - Team Queue - [队列的邻接表]

    题目链接:http://poj.org/problem?id=2259 Queues and Priority Queues are data structures which are known t ...

  8. 洛谷P3953 逛公园 [noip2017] 图论+dp

    正解:图论(最短路)+dp(记忆化搜索) 解题报告: 这题真的是个好东西! 做了这题我才发现我的dij一直是错的...但是我以前用dij做的题居然都A了?什么玄学事件啊...我哭了TT 不过其实感觉还 ...

  9. Treats for the Cows 区间DP POJ 3186

    题目来源:http://poj.org/problem?id=3186 (http://www.fjutacm.com/Problem.jsp?pid=1389) /** 题目意思: 约翰经常给产奶量 ...

随机推荐

  1. haproxy ssl相关配置

    ssl-default-bind-options [<option>]... This setting is only available when support for OpenSSL ...

  2. [转]openlayer+geoserver实现WFS操作

    From:http://liushaobo2005.blog.163.com/blog/static/253056702011541462372/ wfs是OGC的标准规范,主要用于提供对矢量地理数据 ...

  3. 【LeetCode练习题】Add Two Numbers

    链表相加 You are given two linked lists representing two non-negative numbers. The digits are stored in ...

  4. Ubuntu12.04 Jdk1.7 Tomct7.0部署配置

    jdk1.7 下载 http://download.oracle.com/otn-pub/java/jdk/7u67-b01/jdk-7u67-linux-x64.tar.gz?AuthParam=1 ...

  5. Hadoop 5、HDFS HA 和 YARN

    Hadoop 2.0 产生的背景Hadoop 1.0 中HDFS和MapReduce存在高可用和扩展方面的问题 HDFS存在的问题 NameNode单点故障,难以用于在线场景 NameNode压力过大 ...

  6. ILSpy,DLL反编译工具,学习与了解原理的好帮手

    你是否一直苦于找到了好的dll却只知道怎么使用而不知道其原理. 你是否在使用一个dll的时候发现它在一些参数时报错了却没法解决. 你是否想成为一个优秀的.net开发,成为一个优秀的系统制造者. 那你需 ...

  7. jquery promot

    http://www.itivy.com/jquery/archive/2011/10/15/jquery-impromptu-usage.html

  8. C#中的反射原理及应用(转)

    反射的概述 反射的定义:审查元数据并收集关于它的类型信息的能力.元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等, ...

  9. 【收藏】十大Webserver漏洞扫描工具

    如今有很多消息令我们感到Web的危急性,因此,当前怎样构建一个安全的Web环境成为网管员和安全管理员们义不容辞的责任.可是巧妇难为无米之炊,该选择哪些安全工具呢? 扫描程序能够在帮助造我们造就安全的W ...

  10. 如何实现在O(n)时间内排序,并且空间复杂度为O(1)

    对于常见的排序算法,很难做到在O(n)时间内排序,并且空间复杂度为O(1),这里提供了一种方法可以达到要求. 可以使用哈希排序的思想,也就是将所有的数哈希到哈希表中,实现排序.具体的算法思想是,求出这 ...