/*
* poj1112 AC
* DP 揹包問題 與poj1636 prison rearrangement如出一轍。
* 問題挺經典,重點在於構造模型。
* 首先考慮將所有人分爲互斥的若干部分,這便是揹包問題中物品了。
* 之後,要將每個"物品"分爲放在A和放在B的兩個部分,然後進行DP。
*
* I. 求補圖,將表示兩個人相互認識的邊去除,連接所有互相不認識,
* 或單方面認識的邊。
* II.對每個處於同一連通分量的人進行染色,同時將每一個聯通分量
* 構造成類似於二分圖的形式,分爲兩個部分。
*III.類似與poj1636的方式進行DP,每個“物品”分爲兩種放法,想象一
* 下堆積木,得到最小的差值,記錄下選擇的路徑。
*
* 注意:不要MLE了,使用char來替代short。
*
* */
#include<cstdio>
#include<algorithm>
#include<memory.h>
using namespace std;
int n,tot;
bool map[105][105],flag,dp[105][105][105];
int node[10005],next[10005],head[105];
short a[105][2],label[105];
char pre[105][105][105][4],rec[105][105][105],fir[105],sec[105],col[105];
void addnode(int x,int y)
{
node[++tot] = y,next[tot] = head[x],head[x] = tot;
}
//void dfs(int x,int team)
void dfs(char x,int team)
{
a[tot][team]++,rec[tot][team][a[tot][team]] = x,label[(int)x] = tot,col[(int)x] = team;
int i;
for(i=head[(int)x];i;i=next[i])
{
if(label[node[i]]==0)
{
dfs(node[i],1-team);
if(!flag) return;
}else if(label[node[i]]==label[(int)x] && col[node[i]]==col[(int)x])
{
flag = false;
return;
}
}
return;
}
int main()
{
scanf("%d",&n);
// FILE* fin = fopen("d.in","r");
// fscanf(fin,"%d",&n);
int i,j,k;
memset(map,false,sizeof(map));
for(i=1;i<=n;i++)
{
while(scanf("%d",&j) && j)
// while(fscanf(fin,"%d",&j) && j)
map[i][j] = true;
}
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
{
if(map[i][j] && map[j][i])
map[i][j] = map[j][i] = false;
else
map[i][j] = map[j][i] = true;
}
memset(head,0,sizeof(head));
memset(next,0,sizeof(next));
memset(node,0,sizeof(node));
for(tot=0,i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j && map[i][j])
addnode(i,j);
memset(col,0,sizeof(col));
memset(label,0,sizeof(label));
for(tot=0,flag=true,i=1;i<=n;i++)
if(label[i]==0)
{
tot++;
dfs(i,0);
if(!flag) break;
}
if(!flag)
printf("No solution\n");
else
{
memset(pre,0,sizeof(pre));
memset(dp,false,sizeof(dp));
dp[0][0][0] = true;
for(i=1;i<=tot;i++)
for(j=n;j>=0;j--)
for(k=n;k>=0;k--)
{
if(j-a[i][0]>=0 && k-a[i][1]>=0)
{
if(dp[i-1][j-a[i][0]][k-a[i][1]])
{
dp[i][j][k] = true;
pre[i][j][k][0] = j-a[i][0];
pre[i][j][k][1] = k-a[i][1];
pre[i][j][k][2] = 0;
}
}
if(j-a[i][1]>=0 && k-a[i][0]>=0)
{
if(dp[i-1][j-a[i][1]][k-a[i][0]])
{
dp[i][j][k] = true;
pre[i][j][k][0] = j-a[i][1];
pre[i][j][k][1] = k-a[i][0];
pre[i][j][k][2] = 1;
}
}
}
int num1,num2,min = 0xffff;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(dp[tot][i][j] && abs(i-j)<min)
num1 = i,num2 = j,min = abs(i-j);
int tot1,tot2;
for(tot1=tot2=0,i=tot;i>0;i--)
{
if(pre[i][num1][num2][2]==0)
{
for(j=1;j<=a[i][0];j++)
fir[++tot1] = rec[i][0][j];
for(j=1;j<=a[i][1];j++)
sec[++tot2] = rec[i][1][j];
}else if(pre[i][num1][num2][2]==1)
{
for(j=1;j<=a[i][1];j++)
fir[++tot1] = rec[i][1][j];
for(j=1;j<=a[i][0];j++)
sec[++tot2] = rec[i][0][j];
}
int t = num1;
num1 = pre[i][num1][num2][0];
num2 = pre[i][t][num2][1];
}
sort(fir+1,fir+tot1+1);
sort(sec+1,sec+tot2+1);
printf("%d ",tot1);
for(i=1;i<=tot1;i++)
printf("%d ",fir[i]);
printf("\n%d ",tot2);
for(i=1;i<=tot2;i++)
printf("%d ",sec[i]);
printf("\n");
}
return 0;
}
poj1112 Team Them Up!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.