/*
* 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!
最新推荐文章于 2017-10-02 17:43:37 发布