poj 1112 二分图染色+dp
来源:互联网 发布:落樱神斧华盛顿知乎 编辑:程序博客网 时间:2024/04/30 03:22
题意:
给出n个人,和一些关系有向的关系,有向边a->b表示a认识b:
将n个人划分为两组,要求每组组内人必须互相都认识,同时要求两组人数差最小。
思路:
可以知道的是必须有a->b,且b->a的关系存在时,a和b才能被分为一组。考虑反向建图,若a,b不能分为一组,则连一条a,b之间的无向边。现在就变成了一系列连通块,对于他们去做二分图奇偶染色,将每个连通块根据奇偶划分为两部分,这两部分必然不能在一个集合,然后在这一系列的块中,每个连通块选一部分,形成总的集合a,剩下的点作为集合b,使用dp求取选择的最优值。若在此过程中,存在一个连通块不是二分图,那么一定无解。这个操作也可以通过带权并查集实现,维护每个连通块中的点到parent的关系,此关系其实也就是二分图中的奇偶关系。
代码:
代码略丑。。。
#include <cstdio>#include <vector>#include <cstring>using namespace std;const int size = 200;int n;int mp[size][size];bool vis[size];vector<int> con[size][2];int cnt;int dp[size][size];int st[size][size];int pr[size][size];int se[size];vector<int> at;bool dfs(int a,int so,int pre){ if(vis[a]) { if(se[a] != so) return false; else return true; } se[a] = so; vis[a] = true; con[cnt][so].push_back(a); for(int i = 1; i <= n;i++) { if(pre==i || i == a) continue; if(mp[i][a] == 0) { if(!dfs(i,1-so,a)) return false; } } return true;}int main(){ int t; scanf("%d",&t); //t = 1; while(t--) { cnt = 0; for(int i = 0; i < size;i++) for(int j = 0; j < 2; j++) con[i][j].clear(); memset(mp,0,sizeof(mp)); scanf("%d",&n); for(int i = 1; i <= n; i++) { int ms; while(~scanf("%d",&ms)&&ms) mp[i][ms] = 1; mp[i][i] = 1; } for(int i = 1;i <= n; i++) { for(int j = 1;j <= n; j++) { if(mp[i][j] == 0 || mp[j][i] == 0) mp[i][j] = mp[j][i] = 0; //printf(" %d",mp[i][j]); } //printf("\n"); } memset(vis,false,sizeof(vis)); bool anss = true; for(int i =1;i <= n; i++) if(!vis[i]) { anss = anss &&dfs(i,0,-1); cnt++; } if(!anss) { printf("No solution\n"); if(t!=0) printf("\n"); continue; } memset(dp,0,sizeof(dp)); dp[0][con[0][0].size()] = 1; dp[0][con[0][1].size()] = 1; st[0][con[0][0].size()] = 0; st[0][con[0][1].size()] = 1; for(int i = 1; i <cnt;i++) { int a = con[i][0].size(); int b = con[i][1].size(); for(int j = 0;j <= n;j++) { bool can = false; if(j - a >= 0&&dp[i-1][j-a]) { can = true; pr[i][j] = j-a; st[i][j] = 0; } if(j - b >= 0 && dp[i-1][j-b]) { can = true; pr[i][j] = j-b; st[i][j] = 1; } if(can) dp[i][j] = 1; } } int mis = 2e9; int ans; for(int j = 1; j < n; j++) { if(dp[cnt-1][j]) { int dis = n - j -j; if(dis < 0) dis = -dis; if(dis <mis) { mis = dis; ans = j; } } } memset(vis,false,sizeof(vis)); at.clear(); for(int i = cnt-1; i >= 0; i--) { for(int j = 0; j < con[i][st[i][ans]].size();j++) { int mks = con[i][st[i][ans]][j]; at.push_back(mks); vis[mks] = true; } ans = pr[i][ans]; } printf("%d",n-at.size()); for(int i = 1;i <= n; i++) if(!vis[i])printf(" %d",i); printf("\n"); printf("%d",at.size()); for(int i = 0;i < at.size(); i++) printf(" %d",at[i]); printf("\n"); if(t!= 0)printf("\n"); } return 0;}
0 0
- poj 1112 二分图染色+dp
- poj 1112 Team Them Up! 二分图染色+dp
- poj 1112 染色+DP
- POJ 1112 Team Them Up! (二分图染色+连通分量+DP)
- zoj1462 二分图染色+DP
- 二分图+染色 poj 2492
- 图论专题(一)POJ1112二分染色+DP
- hdu5313 Bipartite Graph(二分图染色+dp+位运算)
- hdu5313Bipartite Graph(二分图染色+DP(bitset优化))
- hdu 5313 Bipartite Graph(二分图染色+dp+bitset优化)
- Uva 1627 Team them up!(dp+二分图染色)
- poj1112 Team Them Up!(二分图染色+dp)
- poj 3207 2-sat 或 染色判二分图
- POJ 2492 A Bug's Life【二分图染色法】
- poj 2942 双连通分量+二分图的染色判断
- POJ 2942 点双联通+二分图染色
- POJ 3020 Antenna Placement 【二分图 黑白染色】
- poj 2942 点双连通分量+二分图染色
- C++ Primer 第五版 练习 3.21,3.24
- 【Java Learning】泛型类ArrayList 的用法介绍
- Linux Shell for循环写法总结
- android自定义dialog style
- amaze UI插件
- poj 1112 二分图染色+dp
- js的sort排序
- jquery
- Nova Suspend/Rescue 操作详解 - 每天5分钟玩转 OpenStack(35)
- basic file operations
- 2013蓝桥决赛C/C++B组
- java大杂烩
- 进程间通信--信号
- 数据库的原理