POJ 1112 Team Them Up!

来源:互联网 发布:赛亚人网络 编辑:程序博客网 时间:2024/06/07 04:33

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

题意:一共N个人,给出每个人和其余人是否认识,把所有人分成两组。
要求1)每一个人 属于其中一组。
2)每组必须有人 
3)每组内的所有人 必须相互认识(有向边 相互认识 才是认识) 
4)两组的人数之差尽可能小


先读入数据,把两两不认识的人 连边, 建图,则同一边连接的两点不能在同一组。建完图后,进行DFS 染色,可以把图 分成sum个连通分量,每个联通分量的点 标记 0 1 交替,如果出现同一边的两点 标记相同,则无法分到两个组中,"No solution".
每个连通分量,有两个组即0 和1 分别标记的,两点集的人必须分到不同的小组。


之后DP, dp[i][j][k]  i代表分配第i个联通分量,j代表两组的人数差此时为j,k有三个值:0 记录路径 由上一个联通块的差值j得到, 1 代表 此时最终求的 两组 哪个组(0 or 1)人数少, 2 代表 这次把第i个联通分量的 个数少的点集 分到 哪一组。
dp[i-1][j][]可以推出 dp[i][j+cha][] dp[i][abs(j-cha)][] , //cha 是这个联通分量内0 1 标记的两点集人数的差值。
最后找dp[sum][i][0] i由0到n 找dp的值存在的最小的i,
之后进行DFS 输出路径

发现dp是硬伤。。

code:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<queue>using namespace std;#define INF 1000000000#define N 103int d[N][N],n,tot,hh[N],sum,vis[N],s[N][3],sss[N][3][N],flag,mar[N],dp[N][N][3];int out[2][N],ar[2];struct node{int u,v,next;}edge[2*N*N];void add(int u,int v){edge[tot].u=u; edge[tot].v=v;edge[tot].next=hh[u]; hh[u]=tot++;}void dfs(int u,int mark,int ss,int last){if(flag) return ;vis[u]=1;mar[u]=mark;s[ss][mark]++;int cou=s[ss][mark];sss[ss][mark][cou]=u;for(int i=hh[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(v==last) continue;if(vis[v]){if(mar[v]==mark){flag=1; return ;}continue;}dfs(v,!mark,ss,u);}}void dfss(int x,int y){if(x<=0) return;int a1=dp[x][y][0],a2=dp[x][y][2];if(s[x][0]<s[x][1]){for(int i=1;i<=s[x][0];i++)out[a2][++ar[a2]]=sss[x][0][i];for(int i=1;i<=s[x][1];i++)out[a2^1][++ar[a2^1]]=sss[x][1][i];}else{for(int i=1;i<=s[x][0];i++)out[a2^1][++ar[a2^1]]=sss[x][0][i];for(int i=1;i<=s[x][1];i++)out[a2][++ar[a2]]=sss[x][1][i];}dfss(x-1,a1);}int main(){while(scanf("%d",&n)!=EOF){memset(d,0,sizeof(d));for(int i=1;i<=n;i++){int a;while(scanf("%d",&a),a)d[i][a]=1;}tot=0;memset(hh,-1,sizeof(hh));for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++){if(d[i][j] && d[j][i]) continue;add(i,j); add(j,i);}}sum=0; memset(vis,0,sizeof(vis));memset(s,0,sizeof(s));memset(mar,-1,sizeof(mar));flag=0;for(int i=1;i<=n;i++){if(vis[i]) continue;sum++;// from 1dfs(i,0,sum,-1);}if(flag){printf("No solution\n"); continue;}memset(dp,-1,sizeof(dp));dp[0][0][0]=dp[0][0][1]=dp[0][0][2]=0;for(int i=1;i<=sum;i++){for(int j=0;j<=n;j++){if(dp[i-1][j][0]>=0){int cha=abs(s[i][0]-s[i][1]);dp[i][j+cha][0]=j;dp[i][j+cha][1]=dp[i-1][j][1];dp[i][j+cha][2]=dp[i-1][j][1];if(j>cha){dp[i][j-cha][0]=j;dp[i][j-cha][1]=dp[i-1][j][1];dp[i][j-cha][2]=dp[i-1][j][1]^1;}else{dp[i][cha-j][0]=j;dp[i][cha-j][1]=dp[i-1][j][1]^1;dp[i][cha-j][2]=dp[i-1][j][1]^1;}}}}ar[0]=ar[1]=0;for(int i=0;i<=n;i++){if(dp[sum][i][0]>=0){dfss(sum,i);printf("%d",ar[0]);for(int i=1;i<=ar[0];i++) printf(" %d",out[0][i]);puts("");printf("%d",ar[1]);for(int i=1;i<=ar[1];i++) printf(" %d",out[1][i]);puts("");break;}}}return 0;}



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 cf幽灵鬼呼吸辅军训刘海怎么办助 眼睛被等离子切割器的光烤了怎么办 玩王者的时候屏幕竖着了该怎么办 铝合金门双包门套比墙的厚了怎么办 磁共振检查后发现带金属了怎么办 贴了乳贴过免痒怎么办 yy别人听见我打游戏的声音怎么办 微信的聊天记录发错邮箱怎么办 百度云盘文件有违规内容怎么办 天籁一键启动钥匙没电怎么办 中兴手机系统界面已停止运行怎么办 怎么办可以复制成不关联的文档 希捷400g硬盘电机不转怎么办 金立手机微信语音播放失败怎么办 手机4g网络变2g怎么办 生存战争2吃了腐烂的食物后怎么办 古筝调音 d的显示为b怎么办 消防建审没有原有的结构图纸怎么办 生石灰弄到脸上用水洗后发热怎么办 吃了没熟的鹅肝怎么办 蹲式厕所被袜子堵了怎么办 自热包的水喝了怎么办 火锅发热包不小心吃了怎么办 塑料螺旋饭盒盖子被吸住了怎么办 昨晚喝太多酒今天排尿拍不出怎么办 开光过的貔貅摔坏一点嘴巴怎么办 诺基亚6第二代忘记解屏密码怎么办 工厂搬迁已经般空了工人怎么办 被上司强行换了一个岗位该怎么办 上司要调整我岗位我该怎么办 我被别人打伤了警察不管怎么办 郑州共享汽车小黄车路上坏了怎么办 爱跟别人聊朋友的事怎么办 任职履历上学历写错了怎么办 六个月的宝宝老长婴儿湿疹怎么办 入伍前驾照没考完退伍后过期怎么办 在电脑上玩英雄联盟没有声音怎么办 梦幻西游新区抢不到副本积分怎么办 倒车时遇上机动车碰瓷的怎么办 电瓶车相撞对方全责但不赔偿怎么办 轻微刮蹭逃逸对方想多要钱怎么办