洛谷P2055 [ZJOI2009]假期的宿舍 {最大流,Dinic算法}

题目

https://www.luogu.org/problemnew/show/P2055#sub
在学校,到了假期,就有部分学生要回家,有部分非本校学生要看望剩下的学生,根据他们是否认识,来分配他们的床位(床位一定)


解题思路

可以用匈牙利算法来做(应该能过), 如果用Dinic算法做的话,【重点在建图:把空余的床位连接源点,把剩下的学生连接汇点,然后将这两堆东西连接在一起。】,套模板。


代码

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std; 
const int inf=100000000; 
queue<int>que;
struct node{
    int x,y,c,next;
}a[200001];
int n,s,t,ans,len=0,last[200001],dis[200001],b[200001]; 
int read()
{
    int f=0,p=1; char c; 
    while(c=getchar(),c<=47||c>=58) if(c=='-') p=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
    return p*f;
}
int minn(int xa,int ya)
{return xa>ya?ya:xa;}
void add(int xa,int ya,int ca)
{
    a[++len].y=ya; a[len].c=ca; a[len].next=last[xa]; last[xa]=len;
    a[++len].y=xa; a[len].c=0; a[len].next=last[ya]; last[ya]=len;
}
bool bfs()
{
    memset(dis,-1,sizeof(dis)); 
    while (!que.empty()) que.pop(); 
    que.push(s); dis[s]=0;
    while(!que.empty())
    {
        int u=que.front(); que.pop(); 
        for (int i=last[u];~i;i=a[i].next)
        if (a[i].c&&dis[a[i].y]==-1)
        {
            dis[a[i].y]=dis[u]+1; 
            if (a[i].y==t) return 1; 
            que.push(a[i].y); 
        }
    }
    return 0; 
}
int dfs(int xq,int maxf)
{
    if (xq==t||!maxf) return maxf; 
    int ret=0; 
    for (int i=last[xq];~i;i=a[i].next)
    if (a[i].c&&dis[a[i].y]==dis[xq]+1)
    {
        int f=dfs(a[i].y,minn(a[i].c,maxf-ret)); 
        a[i].c-=f; 
        a[i^1].c+=f; 
        ret+=f; 
        if (maxf==ret) break; 
    }
    if (!ret) dis[xq]=-1;
    return ret;
}
int dinic()
{
    int anss=0; 
    while (bfs()) anss+=dfs(s,inf); 
    return anss; 
}
int main()
{
  int k; k=read(); 
  for (int kk=1;kk<=k;kk++)
  {
    len=-1;ans=0;
    memset(last,-1,sizeof(last));
    n=read(); 
    s=0; t=n<<1|1; 
    for (int i=1;i<=n;i++)
    {
        b[i]=read(); 
        if (b[i]) add(i+n,t,1); 
    }
    int q; 
    for (int i=1;i<=n;i++)
    {
        q=read(); 
        if (!b[i]||(b[i]&&!q))
          {
            add(s,i,1); 
            ans++; 
          }
    }
    for (int i=1;i<=n;i++)
     for (int j=1;j<=n;j++)
     {
        q=read(); 
        if (i==j||q) add(i,j+n,1); 
     }
     if (dinic()==ans) printf("^_^\n"); else printf("T_T\n"); 
  }
}

猜你喜欢

转载自blog.csdn.net/qq_39897867/article/details/80769327