现在的位置: 首页 > 算法 > 正文

poj1112 Team Them Up!

2019年09月22日 算法 ⁄ 共 2708字 ⁄ 字号 评论关闭
/*
 * 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;
}

抱歉!评论已关闭.