• BZOJ 1458 士兵占领


    http://www.lydsy.com/JudgeOnline/problem.php?id=1458

    题意:n x m的棋盘,k个位置不能放,每行和每列都有要求至少的士兵,求能否有最少的满足条件的士兵放法是多少。

    思路:先全放满求能否满足,再尽量删掉士兵:

    对于每行:能放m[i],至少放c[i],就从S连向i:m[i]-c[i],代表能删的最大

    对于每列:能放m[i],至少放c[i],就从i+n连向T:m[i]-c[i],代表能删的最大   

    这样对于i,j这个位置如果可以放士兵,那就从i行连向j+n,流量为1,共享删掉1个

    求最大流,就等于最小割,得到的就是能删的最多,然后答案就是Σm1[i]-最大流

     1 #include<algorithm>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<iostream>
     6 #define inf 0x7fffffff
     7 int tot,go[200005],next[200005],flow[200005],first[200005];
     8 int op[200005],nodes,T,S,dis[200005],cnt[200005],pd[105][105],n,m,k;
     9 int m1[200005],m2[200005],c1[200005],c2[200005];
    10 int read(){
    11     int t=0,f=1;char ch=getchar();
    12     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    13     while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
    14     return t*f;
    15 }
    16 void insert(int x,int y,int z){
    17     tot++;
    18     go[tot]=y;
    19     next[tot]=first[x];
    20     first[x]=tot;
    21     flow[tot]=z;
    22 }
    23 void add(int x,int y,int z){
    24     insert(x,y,z);op[tot]=tot+1;
    25     insert(y,x,0);op[tot]=tot-1;
    26 }
    27 int dfs(int x,int f){
    28     if (x==T) return f;
    29     int mn=nodes,sum=0;
    30     for (int i=first[x];i;i=next[i]){
    31         int pur=go[i];
    32         if (flow[i]&&dis[pur]+1==dis[x]){
    33             int save=dfs(pur,std::min(f-sum,flow[i]));
    34             flow[i]-=save;
    35             flow[op[i]]+=save;
    36             sum+=save;
    37             if (sum==f||dis[S]>=nodes) return sum;
    38         }
    39         if (flow[i]) mn=std::min(mn,dis[pur]);
    40     }
    41     if (sum==0){
    42         cnt[dis[x]]--;
    43         if (cnt[dis[x]]==0){
    44             dis[S]=nodes;
    45         }else{
    46             dis[x]=mn+1;
    47             cnt[dis[x]]++;
    48         }
    49     }
    50     return sum;
    51 }
    52 int main(){
    53     n=read();m=read();k=read();
    54     S=0,T=n+m+1;nodes=T+1;
    55     int sum1=0,sum2=0;
    56     for (int i=1;i<=n;i++){
    57         int x=read();
    58         sum1+=x;
    59         m1[i]=x;
    60     }
    61     for (int i=1;i<=m;i++){
    62         int x=read();
    63         sum2+=x;
    64         m2[i]=x;
    65     }
    66     for (int i=1;i<=k;i++){
    67         int x=read(),y=read();
    68         pd[x][y]=1;
    69     }
    70     int ans=0;
    71     for (int i=1;i<=n;i++)
    72      for (int j=1;j<=m;j++)
    73       if (!pd[i][j])
    74        c1[i]++,c2[j]++;
    75     int sx=0;
    76     for (int i=1;i<=n;i++)
    77      sx+=c1[i];   
    78     for (int i=1;i<=n;i++)
    79      if (c1[i]<m1[i]) {
    80             printf("JIONG!
    ");return 0;
    81      }   
    82      for (int i=1;i<=m;i++)
    83       if (c2[i]<m2[i]){
    84             printf("JIONG!
    ");return 0;
    85       }
    86     for (int i=1;i<=n;i++)
    87      add(S,i,c1[i]-m1[i]);
    88     for (int i=1;i<=m;i++)
    89      add(i+n,T,c2[i]-m2[i]);   
    90     for (int i=1;i<=n;i++)
    91      for (int j=1;j<=m;j++)
    92       if (!pd[i][j])
    93        add(i,j+n,1);       
    94     while (dis[S]<nodes) ans+=dfs(S,inf); 
    95     ans=sx-ans;
    96     printf("%d
    ",ans);  
    97 }
  • 相关阅读:
    在给定的区间上对每个数都开方 最后还是在一段上求和
    简单的覆盖问题,,通过覆盖的g不同 有这不同的价值 最后还是一段上求和
    codevs 3094 寻找sb4
    noi 04:网线主管
    codevs 1031 质数环
    codevs 1061 重复子串
    codevs 1204 寻找子串位置
    codevs 3223 素数密度
    各种用法
    codevs1073 家族
  • 原文地址:https://www.cnblogs.com/qzqzgfy/p/5588984.html
Copyright © 2020-2023  润新知