BZOJ1433假期的宿舍

1433: [ZJOI2009]假期的宿舍
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1894 Solved: 817
Description
这里写图片描述
Input
这里写图片描述
Output
这里写图片描述
Sample Input
1
3
1 1 0
0 1 0
0 1 1
1 0 0
1 0 0
Sample Output
ˆ_ˆ
HINT
对于30% 的数据满足1 ≤ n ≤ 12。
对于100% 的数据满足1 ≤ n ≤ 50,1 ≤ T ≤ 20。
请原谅我没有1A。。
首先多组数据,每次需要memset。。
然后建图的问题。。
读入的矩阵如果是1或者i==j,就把i向j+n连边。。流量为1
在校的向源点连边。。需要床位的向汇点连边。。
记录一下需要的床位。。
然后就A啦啦啦啦啦。。
附上本蒟蒻的代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,h[100001],b[51],a[51],q[100001],dis[100001],head,tail,cnt,ans,sum,f[51][51],num;
struct kx
{
    int next,to,v;
};
kx edge[100001];

int read()
{
    int w=0,c=1;
    char ch=getchar();
    while (ch<'0' || ch>'9')
      {
        if (ch=='-')
          c=-1;
        ch=getchar();
      }
    while (ch>='0' && ch<='9')
      {
        w=w*10+ch-'0';
        ch=getchar();
      }
    return w*c;
}

void add(int u,int v,int w)
{
    cnt++,edge[cnt].next=h[u],h[u]=cnt,edge[cnt].to=v,edge[cnt].v=w;
}

bool bfs()
{
    int j,p;
    memset(dis,-1,sizeof(dis));
    q[0]=0,dis[0]=0;
    head=0,tail=1;
    while (head<tail)
      {
        head++;
        j=q[head];
        p=h[j];
        while (p)
          {
            if (dis[edge[p].to]<0 && edge[p].v>0)
              {
                dis[edge[p].to]=dis[j]+1;
                tail++;
                q[tail]=edge[p].to;
              }
            p=edge[p].next;
          }
      }
    if (dis[2*n+1]>0)
      return true;
    else
      return false;
}

int dfs(int x,int f)
{
    int w,used=0,i=h[x];
    if (x==2*n+1)
      return f;
    while (i)
      {
        if (edge[i].v && dis[edge[i].to]==dis[x]+1)
          {
            w=f-used;
            w=dfs(edge[i].to,min(w,edge[i].v));
            edge[i].v-=w;
            edge[i^1].v+=w;
            used+=w;
            if (used==f)
              return f;
          }
        i=edge[i].next;
      }
    if (!used)
      dis[x]=-1;
    return used;
}

void build()
{
    int i,j;
    for (i=1;i<=n;i++)
      for (j=1;j<=n;j++)
        if (f[i][j] || i==j)
          add(i,j+n,1),add(j+n,i,0);
    for (i=1;i<=n;i++)
      if (a[i])
        add(0,i,1),add(i,0,0);
    for (i=1;i<=n;i++)
      if (a[i] && !b[i] || !a[i])
        add(i+n,2*n+1,1),add(2*n+1,i+n,0),num++;
}

int main()
{
    int t,i,j;
    t=read();
    while (t--)
      {
        memset(h,0,sizeof(h));
        cnt=1;
        num=0;
        n=read();
        for (i=1;i<=n;i++)
          a[i]=read();
        for (i=1;i<=n;i++)
          b[i]=read();
        for (i=1;i<=n;i++)
          for (j=1;j<=n;j++)
            f[i][j]=read();
        build();
        ans=0;
        while (bfs())
          while (sum=dfs(0,0x7fffffff))
            ans+=sum;
        if (ans==num)
          printf("%s\n","^_^");
        else
          printf("%s\n","T_T");
      }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值