zoukankan      html  css  js  c++  java
  • 计蒜客

    题目链接:https://nanti.jisuanke.com/t/31447

    知识点:  最大流

    题目大意:

      给定一个二分图,左边有 $N$ 个点,右边有 $M$ 个点,给出 $K$ 条边。问是否能从这 $K$ 条边中找出若干条边使得每个点的度数都在 $[L,R]$ 中。

      $1 le N le 2000, 0 le M le 2000, 0 le K le 6000, 0 le L,R le 300$

    解题思路:

      不难想到这是一个无源无汇有容量下界网络的可行流问题。

      先建一个小源点 $s$ 和小汇点 $t$,一个大源点 $ss$ 和一个大汇点 $st$。从 $st$ 连一条边到 $ss$,从 $ss$ 连一条边到 $s$,从 $t$ 连一条边到 $st$,容量均为 $INF$。 然后将题目给定的边连进网络图中,容量均为 $1$。

      对于 $s$ 连向左边每一点(设为 $u$)的边,需要限制它们的流量下界为 $L$,上界为 $R$,做法是从 $s$ 向 $u$ 连一条容量为 $R-L$ 的边,从 $ss$ 向 $u$ 连一条容量为 $L$ 的边,再从 $s$ 连一条容量为 $L$ 的边到大汇点。如果所有容量为 $L$ 的附加边都满流,则证明有可行流,输出"Yes"。

    AC代码:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 typedef long long LL;
      4 
      5 const int MAXN = 4010;//点数的最大值
      6 const int MAXM = 40010;//边数的最大值
      7 const int INF = 0x3f3f3f3f;
      8 struct Edge
      9 {
     10     int to,next,cap,flow;
     11 }edge[MAXM];//注意是MAXM
     12 int tol;
     13 int head[MAXN];
     14 int gap[MAXN],dep[MAXN],cur[MAXN];
     15 void init(){
     16     tol = 0;
     17     memset(head,-1,sizeof(head));
     18 }
     19 void addedge(int u,int v,int w,int rw = 0){
     20     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
     21     edge[tol].next = head[u]; head[u] = tol++;
     22     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
     23     edge[tol].next = head[v]; head[v] = tol++;
     24 }
     25 int Q[MAXN];
     26 void BFS(int start,int end){
     27     memset(dep,-1,sizeof(dep));
     28     memset(gap,0,sizeof(gap));
     29     gap[0] = 1;
     30     int front = 0, rear = 0;
     31     dep[end] = 0;
     32     Q[rear++] = end;
     33     while(front != rear){
     34         int u = Q[front++];
     35         for(int i = head[u]; i != -1; i = edge[i].next){
     36             int v = edge[i].to;
     37             if(dep[v] != -1)continue;
     38             Q[rear++] = v;
     39             dep[v] = dep[u] + 1;
     40             gap[dep[v]]++;
     41         }
     42     }
     43 }
     44 int S[MAXN];
     45 int sap(int start,int end,int N){
     46     BFS(start,end);
     47     memcpy(cur,head,sizeof(head));
     48     int top = 0;
     49     int u = start;
     50     int ans = 0;
     51     while(dep[start] < N){
     52         if(u == end){
     53             int Min = INF;
     54             int inser;
     55             for(int i = 0;i < top;i++)
     56                 if(Min > edge[S[i]].cap - edge[S[i]].flow){
     57                     Min = edge[S[i]].cap - edge[S[i]].flow;
     58                     inser = i;
     59                 }
     60             for(int i = 0;i < top;i++){
     61                 edge[S[i]].flow += Min;
     62                 edge[S[i]^1].flow -= Min;
     63             }
     64             ans += Min;
     65             top = inser;
     66             u = edge[S[top]^1].to;
     67             continue;
     68         }
     69         bool flag = false;
     70         int v;
     71         for(int i = cur[u]; i != -1; i = edge[i].next){
     72             v = edge[i].to;
     73             if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]){
     74                 flag = true;
     75                 cur[u] = i;
     76                 break;
     77             }
     78         }
     79         if(flag){
     80             S[top++] = cur[u];
     81             u = v;
     82             continue;
     83         }
     84         int Min = N;
     85         for(int i = head[u]; i != -1; i = edge[i].next)
     86           if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min){
     87               Min = dep[edge[i].to];
     88               cur[u] = i;
     89           }
     90         gap[dep[u]]--;
     91         if(!gap[dep[u]])return ans;
     92         dep[u] = Min + 1;
     93         gap[dep[u]]++;
     94         if(u != start)u = edge[S[--top]^1].to;
     95     }
     96     return ans;
     97 }
     98 int rec[MAXM<<1],cnt;
     99 int main(){
    100     int N,M,K,kase=1;
    101     while(~scanf("%d%d%d",&N,&M,&K)){
    102         int L,R,cnt=0;
    103         scanf("%d%d",&L,&R);
    104         init();
    105         int s=N+M+1,t=N+M+2,ss=N+M+3,st=N+M+4;
    106         addedge(st,ss,INF);
    107         for(int i=0;i<K;i++){
    108             int u,v;
    109             scanf("%d%d",&u,&v);
    110             addedge(u,v+N,1);
    111         }
    112         for(int i=1;i<=N;i++){
    113             rec[cnt++]=tol;
    114             addedge(ss,i,L);
    115             rec[cnt++]=tol;
    116             addedge(s,st,L);
    117             addedge(s,i,R-L);
    118         }
    119         for(int i=1;i<=M;i++){
    120             rec[cnt++]=tol;
    121             addedge(ss,t,L);
    122             rec[cnt++]=tol;
    123             addedge(i+N,st,L);
    124             addedge(i+N,t,R-L);
    125         }
    126         addedge(ss,s,INF);
    127         addedge(t,st,INF);
    128         sap(ss,st,N+M+4);
    129         LL tot=0;
    130         for(int i=0;i<cnt;i++)  tot+=edge[rec[i]].flow;
    131         printf("Case %d: ",kase++);
    132         if(tot==1ll*L*cnt)  puts("Yes");
    133         else    puts("No");
    134     }
    135 
    136     return 0;
    137 }
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    c# 查找进程
    第三方打包工具
    WebClient 上传和下载
    .net 读取文件
    winfrom 圆角panel
    窗体或控件的两种拖动方式
    winfrom 获取当前屏幕尺寸
    动态修改配置文件web服务地址
    将字符串编码成 GBK
    .net(C#) 读取配置文件
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/9613033.html
Copyright © 2011-2022 走看看