Time Limit: 1000MS | Memory Limit: 10000K | |||
Total Submissions: 3404 | Accepted: 901 | Special Judge |
Description
Input
Output
Sample Input
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
3 1 3 5 2 2 4
Source
/*
非常经典的一道DP(0,1背包)题,一个小小的错误让我调了几个小时,思路如下:
1)首先对原图求补图,只有当原图中两个人i和j不同时认识时,在补图中rever[i][j] = rever[j][i] = true, 否则为false;
这样做非常巧妙,通过这个转换将陌生的问题转换为了熟悉的问题
2)利用dfs对补图求所有的连通分量,这样很容易看出,处于不同连通分量中的两个点肯定是可以组在一个队中的;在用dfs
求连通分量的同时对同一个连通分量中的点进行0,1着色,这样当求得一个连通分量后,这个连通分量就分成了d0和d1两组
点。这时候需要做一个判断,对于同一个连通分量中的两个点i和j,如果i和j的0,1着色相同且在补图中i和j之间相连,则此题
肯定无解(花个图很容易就明白了,很好证明)
3)接下来的工作就很熟悉了,相当于将所有连通分量里面的0和1着色组分别分配到1队和2队,里,是1队和2队之间的人数差最小。
这是个典型的0,1背包问题,第i个连通分量里的0,1着色组的数目分别表示为con(i, 0)和con(i, 1),则DP公式如下
f[c][curDiff + con[c][0] - con[c][1]] = true if f[c - 1][curDiff] = true;
f[c][curDiff - con[c][0] + con[c][1]] = true if f[c - 1][curDiff] = true;
dp的同时需要记录路径
dp完后,找出f[lastC]中绝对值最小的,然后往前推就可以得出两队各自的人数,并输出id即可
*/
#include <iostream>
#include <memory>
#include <cmath>
#define MAX_N 102
using namespace std;
static bool input[MAX_N + 2][MAX_N + 2];
static bool rever[MAX_N + 2][MAX_N + 2];
static bool visited[MAX_N + 2];
static int con[MAX_N + 2][MAX_N + 2][2]; // WHICH, COLOR
static int count[MAX_N + 2][3]; //TOTAL NUM, 0 NUM, 1 NUM 2
static int dpR[MAX_N + 2][MAX_N * 2 + 2];
static int path[MAX_N + 2][MAX_N * 2 + 2][2];
int n, conNum = 0;
int finalRes[2][MAX_N + 2];
int total0 = 0 , total1 = 0;
void init()
{
memset(input, false, sizeof(input));
memset(rever, false, sizeof(rever));
memset(visited, false, sizeof(visited));
memset(con, 0, sizeof(con));
memset(count, 0, sizeof(count));
memset(dpR, 0, sizeof(dpR));
memset(path, 0, sizeof(path));
memset(finalRes, 0, sizeof(finalRes));
}
bool exist(int curSeq, int diffVal)
{
int num = dpR[curSeq][0];
for(int i = 1; i <= num; i++)
if(dpR[curSeq][i] == diffVal)
return true;
return false;
}
void dpSolve()
{
int p, s;
dpR[0][0] = 1;
for(p = 0; p < conNum; p++)
{
for(s = 1; s <= dpR[p][0]; s++)
{
int curDiff = dpR[p][s];
int newD1 = curDiff + count[p + 1][1] - count[p + 1][2];
int newD2 = curDiff - count[p + 1][1] + count[p + 1][2];
if(!exist(p + 1, newD1))
{
dpR[p + 1][0]++;
dpR[p + 1][dpR[p + 1][0]] = newD1;
path[p + 1][dpR[p + 1][0]][0] = 0;
path[p + 1][dpR[p + 1][0]][1] = s;
}
if(!exist(p + 1, newD2))
{
dpR[p + 1][0]++;
dpR[p + 1][dpR[p + 1][0]] = newD2;
path[p + 1][dpR[p + 1][0]][0] = 1;
path[p + 1][dpR[p + 1][0]][1] = s;
}
}
}
}
void dfs(int conSeq, int preColor, int curN)
{
visited[curN] = true;
int where = ++count[conSeq][0];
con[conSeq][where][0] = curN;
con[conSeq][where][1] = 1 - preColor;
//((1 - preColor) == 0) ? count[conSeq][1]++ : count[conSeq][2]++;
if((1 - preColor) == 0)
count[conSeq][1]++;
else
count[conSeq][2]++;
for(int i = 1; i <= n; i++)
{
if(i == curN || rever[curN][i] != 1 || visited[i])
continue;
dfs(conSeq, 1 - preColor, i);
}
}
bool dfsTag()
{
int i, j, k;
for(i = 1; i <= n; i++)
{
if(!visited[i])
{
conNum++;
dfs(conNum, 1, i);
int nNum = count[conNum][0];
for(j = 1; j <= nNum; j++)
{
for(k = 1; k <= nNum; k++)
{
if(j == k)
continue;
int n1 = con[conNum][j][0];
int n2 = con[conNum][k][0];
if(con[conNum][j][1] == con[conNum][k][1] && rever[n1][n2] == 1)
{
cout<<"No solution"<<endl;
return false;
}
}
}
}
}
return true;
}
void getRever()
{
int i, j;
for(i = 1; i <= n; i++)
{
for(j = 1; j <= n; j++)
{
if(i == j)
continue;
if(!(input[i][j] && input[j][i]))
rever[i][j] = rever[j][i] = true;
}
}
}
void getFinalRes(int curCon, int curDiffPos)
{
if(curCon == 0)
return;
int type = path[curCon][curDiffPos][0];
if(type == 0)
{
total0 += count[curCon][1];
total1 += count[curCon][2];
finalRes[0][curCon] = 0;
finalRes[1][curCon] = 1;
}
else
{
finalRes[1][curCon] = 0;
finalRes[0][curCon] = 1;
total1 += count[curCon][1];
total0 += count[curCon][2];
}
getFinalRes(curCon - 1, path[curCon][curDiffPos][1]);
}
void printRes()
{
int t, i, j;
for(t = 0; t < 2; t++)
{
if(t == 0) cout<<total0;
else if(t == 1) cout<<total1;
for(i = 1; i <= conNum; i++)
{
int type = finalRes[t][i];
for(j = 1; j <= count[i][0]; j++)
{
int color = con[i][j][1];
if(color == type)
cout<<" "<<con[i][j][0];
}
}
cout<<endl;
}
}
int main()
{
int i, j;
//init();
cin>>n;
for(i = 1; i <= n; i++)
{
while(cin>>j && j != 0)
input[i][j] = true;
}
getRever();
if(dfsTag())
{
dpSolve();
int minDiff = INT_MAX;
int pos;
for(i = 1; i <= dpR[conNum][0]; i++)
{
if(abs(dpR[conNum][i]) < minDiff)
{
minDiff = abs(dpR[conNum][i]); //FAINT,一直错在这儿,一开始没有加abs,一直WA
pos = i;
}
}
getFinalRes(conNum, pos);
printRes();
}
return 0;
}