UVA-1627

(二分图染色+01背包),若两人中至少有其中一人不认识对方则建立一条边。

#include"cstdio"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"vector"
using namespace std;
const int MX = 1e5+7;
const int maxn = 505;
struct edge{
    int v,nxt;
    edge(){}
    edge(int v ,int nxt):v(v), nxt(nxt){}
}e[MX];
int n;
int cnt,tail,head[maxn],col[maxn],sz[maxn],dp[maxn][maxn];
vector <int> d[maxn];
bool flag;
bool mp[maxn][maxn];

void init()
{
    cnt = 1;
    flag = 0;
    tail = -1;
    memset(col,-1,sizeof(col));
    memset(head,-1,sizeof(head));
    memset(mp,0,sizeof(mp));
    for(int i = 0; i <= 2*n+1; i++) d[i].clear();
}

void Add(int u, int v){
    e[++tail] = edge(v,head[u]);
    head[u] = tail;
}

void dfs(int u, int c)
{
    if(flag) return;
    col[u] = c;
    d[cnt+c].push_back(u);
    for(int i = head[u]; ~i; i = e[i].nxt){
        int v = e[i].v;
        if(col[v] != -1 && col[v]!=c^1){
            flag = 1;
            return;
        }
        if(col[v] == -1)
            dfs(v,c^1);
    }
}

void Print()
{
    int now = 0;
    for(int i = 0; i <=n ; i++){
        if(dp[cnt][n+i] == 1){
            now = n+i;
            break;
        }
        else if(dp[cnt][n-i] == 1){
            now = n-i;
            break;
        }
    }

    vector <int> q1,q2;
    for(int i = cnt; i > 0; i--){
        if(dp[i-1][now-sz[i]]){
            for(int j = 0; j < d[2*i-1].size(); j++) q1.push_back(d[2*i-1][j]);
            for(int j = 0; j < d[2*i].size(); j++)   q2.push_back(d[2*i][j]);
            now -= sz[i];
         }
        else{
            for(int j = 0; j < d[2*i-1].size(); j++) q2.push_back(d[2*i-1][j]);
            for(int j = 0; j < d[2*i].size(); j++)   q1.push_back(d[2*i][j]);
            now += sz[i];
        }
    }

    printf("%d",q1.size());
    for(int i = 0; i < q1.size(); i++) printf(" %d",q1[i]);
    puts("");
    printf("%d",q2.size());
    for(int i = 0; i < q2.size(); i++) printf(" %d",q2[i]);
    puts("");
}

void DP()
{
    cnt /= 2;
    for(int i = 1; i <= cnt; i++){
        sz[i] = d[2*i-1].size() - d[2*i].size();
    }

    memset(dp,0,sizeof(dp));
    dp[0][n] = 1;

    int m = 2*n;
    for(int i = 1; i <= cnt; i++){
        for(int j = m; j >= 0; j--){
            if(dp[i-1][j]){
                dp[i][j+sz[i]] = 1;
                dp[i][j-sz[i]] = 1;
            }
        }
    }
    Print();
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        init();
        for(int i = 1; i<= n; i++){
            int x;
            scanf("%d",&x);
            while(x){
                mp[i][x] = 1;
                scanf("%d",&x);
            }
        }
        for(int i = 1; i<= n; i++){
            for(int j = 1; j <= n; j++)
            if(i != j){
                if(mp[i][j] && mp[j][i]) continue;
                Add(i,j);
            }
        }

        for(int i = 1; i <= n; i++){
            if(col[i] == -1){
                dfs(i,0);
                cnt += 2;
                if(flag){
                    puts("No solution\n");
                    break;
                }
            }
        }
        if(flag) continue;
        DP();
        if(T) puts("");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值