感觉自己好像做麻烦了,这个题目的思考方式是,对于不能在一组的连线,这样所有点就被分为一些连通块。
假如可以分组,每一个连通块就是一个泛化物品,价值可正可负。
这是因为,能在一组的点,可以在一组,也可以不在一组,不能在一组的点一定不能在一组,这样保证了不能的情况,简化了问题。
/**==========================================
* This is a solution for ACM/ICPC problem
*
* @source£ºuva 1627
* @type: dp
* @author: wust_ysk
* @blog: http://blog.csdn.net/yskyskyer123
* @email: 2530094312@qq.com
*===========================================*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn= 100 ;
int n;
bool know[maxn+5][maxn+5];
vector<int >G[maxn+5],ve1,ve2;
int color[maxn+5],pre[maxn+5],nex[maxn+5];
int val[maxn+5];
vector<int> has[maxn+5];
bool ok;
bool dp[maxn+5][2*maxn+8];
int fun(int x)
{
return x+100;
}
int find(int x)
{
return x==pre[x]?x:pre[x]=find(pre[x]);
}
void merge(int x,int y)
{
int rootx=find(x);
int rooty=find(y);
if(rootx==rooty) return;
pre[rootx]=rooty;
}
void getUnknow()
{
for(int i=1;i<=n;i++) pre[i]=i;
for(int i=1;i<=n;i++) G[i].clear(),has[i].clear();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) if(i!=j)
{
if(!know[i][j]||!know[j][i] )
{
G[i].push_back(j);
merge(i,j);
}
}
}
}
void dfs(int root,int x,int c)
{
color[x]=c;
val[root]+=c;
has[root].push_back(x);
for(int i=0;i<G[x].size();i++)
{
int y=G[x][i];
if(color[y]==color[x]) ok=0;
if(color[y]) continue;
int tc= c==1?-1:1;
dfs(root,y,tc);
}
}
void add(int x ,int k)
{
for(int i=0;i<has[x].size();i++)
{
int y=has[x][i];
if(color[y]==1&&k==1||color[y]==-1&&k==-1) ve1.push_back(y);
else ve2.push_back(y);
}
}
void findsolution(int step,int ans)
{
if(!step) return;
int y=nex[step];
if(dp[y][fun(ans+val[step] ) ])
{
add( step,-1);
findsolution(y,ans+val[step]);
return;
}
if(dp[y][fun(ans-val[step] ) ])
{
add( step,+1);
findsolution(y,ans-val[step]);
return;
}
}
bool work()
{
memset(color,0,(n+1)* sizeof color[0]);
ok=1;
for(int i=1;i<=n;i++) if(pre[i]==i)
{
val[i]=0;
dfs(i,i,1);
}
if(!ok) return false;
memset(dp,0,sizeof dp);
dp[0][fun(0)]=1;
int last=0;
for(int i=1;i<=n;i++) if(pre[i]==i)
{
nex[i]=last;
for(int v=-n;v<=n;v++)
{
if( -n<=v-val[i]&&v-val[i]<=n)
dp[i][fun(v)]|=dp[last][fun(v-val[i])];
if(-n<=v+val[i]&&v+val[i]<=n)
dp[i][fun(v)]|=dp[last][fun(v+val[i]) ];
}
last=i;
}
int ans;
for(int v=0;v<=n;v++) if(dp[last][fun(v)])
{
ans=v;
break;
}
// printf("%d\n",ans);
ve1.clear();
ve2.clear();
findsolution(last,ans);
printf("%d",ve1.size());
for(int i=0;i<ve1.size();i++)
{
printf(" %d",ve1[i]);
}
putchar('\n');
printf("%d",ve2.size());
for(int i=0;i<ve2.size();i++)
{
printf(" %d",ve2[i]);
}
putchar('\n');
return true;
}
int main()
{
int T,kase=0,x;scanf("%d",&T);
while(T--)
{
if(kase++) putchar('\n');
scanf("%d",&n);
memset(know,0,sizeof know);
for(int i=1;i<=n;i++)
{
while(~scanf("%d",&x)&&x)
{
know[i][x]=1;
}
}
getUnknow();
if(!work() ) {puts("No solution");continue;}
}
return 0;
}
注:完全可以不用并查集