poj 1626

傳送門:http://poj.org/problem?id=1636
題意:有兩個監獄,每個監獄有n個人,有m種關係,表示A監獄第i個人不能跟B監獄第j個人在一個監獄,問你最多能換幾組人(從A,B監獄互換一個人,ans<=n/2)
方法:首先這是一個很明顯的二分圖,我們可以很輕鬆的建邊,但交換一次要把所有與這兩個人有關的情況都遍歷一遍.dp[i][j]表示從A監獄換i個人再從B監獄換j個人是否可行.
代碼

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
struct node{
    int a,b;
}guan[405];
int n,m,fa[405];
int find(int x)
{
    if (fa[x]==x) return x;
    else
    {
        guan[fa[x]].a+=guan[x].a;
        guan[fa[x]].b+=guan[x].b;
        guan[x].a=guan[x].b=0;
        return fa[x]=find(fa[x]);
    }
}
bool f[205][205];
int main()
{
    int t;
    cin>>t;
    while (t--)
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=2*n;i++)//初始化
        {
            if (i<=n) guan[i].a=1,guan[i].b=0,fa[i]=i;
            else guan[i].a=0,guan[i].b=1,fa[i]=i;
        }
        for (int i=1;i<=m;i++)//建邊
        {
            int x,y;
            scanf("%d%d",&x,&y);
            y+=n;
            int dx=find(x);
            int dy=find(y);
            if (dx!=dy)
                {
                    if (dx<dy) fa[dy]=dx;
                    else fa[dx]=dy;
                }
        }
        memset(f,false,sizeof(f));
        f[0][0]=true;
        for (int i=1;i<=2*n;i++)
        {
            find(i);
        }
        int fx=0,fy=0;
        for (int i=1;i<=2*n;i++)//solve
        {
            int z=find(i);
            int x=guan[z].a,y=guan[z].b;
            if (x&&y)
            {
                for (int i=n/2;i>=x;i--)
                    for (int j=n/2;j>=y;j--)
                    {
                        if (i-x>=0&&j-y>=0&&f[i-x][j-y]) f[i][j]=true;
                    }

            }
            else if (x) fx++;
            else if (y) fy++;
            guan[z].a=guan[z].b=0;
        }
        int ans=0;
        int y=min(fx,fy);
        for (int i=0;i<=n/2;i++)//統計
             for (int j=0;j<=n/2;j++)
                if (f[i][j])
                {
                    if (i==j)
                        ans=max(ans,i+y);
                    else if (i<=j&&i+fx>=j)
                        ans=max(ans,j+min(fx-j+i,fy));
                    else if (j<=i&&j+fy>=i)
                        ans=max(ans,i+min(fy-i+j,fx));
                }
        printf("%d\n",min(ans,n/2));
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章