ACM-ICPC 2018 沈阳赛区网络预赛 F. Fantastic Graph (上下界网络流)

2018/09/08 19:25
阅读数 36

正解:

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN=10010;//点数的最大值
const int MAXM=400010;//边数的最大值
#define captype int

struct SAP_MaxFlow{
    struct EDGE{
        int to,next;
        captype cap;
    }edg[MAXM];
    int eid,head[MAXN];
    int gap[MAXN];
    int dis[MAXN];
    int cur[MAXN];
    int pre[MAXN];

    void init(){
        eid=0;
        memset(head,-1,sizeof(head));
    }
    void AddEdge(int u,int v,captype c,captype rc=0){
        edg[eid].to=v; edg[eid].next=head[u];
        edg[eid].cap=c;  head[u]=eid++;
        edg[eid].to=u; edg[eid].next=head[v];
        edg[eid].cap=rc; head[v]=eid++;
    }
    captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
        memset(gap,0,sizeof(gap));
        memset(dis,0,sizeof(dis));
        memcpy(cur,head,sizeof(head));
        pre[sNode] = -1;
        gap[0]=n;
        captype ans=0;
        int u=sNode;
        while(dis[sNode]<n){
            if(u==eNode){
                captype Min=INF ;
                int inser;
                for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to])
                if(Min>edg[i].cap){
                    Min=edg[i].cap;
                    inser=i;
                }
                for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to]){
                    edg[i].cap-=Min;
                    edg[i^1].cap+=Min;
                }
                ans+=Min;
                u=edg[inser^1].to;
                continue;
            }
            bool flag = false;
            int v;
            for(int i=cur[u]; i!=-1; i=edg[i].next){
                v=edg[i].to;
                if(edg[i].cap>0 && dis[u]==dis[v]+1){
                    flag=true;
                    cur[u]=pre[v]=i;
                    break;
                }
            }
            if(flag){
                u=v;
                continue;
            }
            int Mind= n;
            for(int i=head[u]; i!=-1; i=edg[i].next)
            if(edg[i].cap>0 && Mind>dis[edg[i].to]){
                Mind=dis[edg[i].to];
                cur[u]=i;
            }
            gap[dis[u]]--;
            if(gap[dis[u]]==0) return ans;
            dis[u]=Mind+1;
            gap[dis[u]]++;
            if(u!=sNode) u=edg[pre[u]^1].to;  //退一条边
        }
        return ans;
    }
}F;

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int cas = 1;
    int N,M,K,u,v;
    while(scanf("%d %d %d",&N,&M,&K)==3){
        int L,R; scanf("%d %d",&L,&R);
        F.init();
        int s= 0,t = N+M+1;
        int S = N+M+2,T = N+M+3;
        F.AddEdge(t,s,INF);
        F.AddEdge(s,T,L*N);
        F.AddEdge(S,t,L*M);
        for(int i=1;i<=N;++i) F.AddEdge(s,i,R-L), F.AddEdge(S,i,L);
        for(int i=1;i<=M;++i) F.AddEdge(i+N,t,R-L),F.AddEdge(i+N,T,L);
        while(K--){
            scanf("%d %d",&u,&v);
            F.AddEdge(u,v+N,1);
        }
        int f = F.maxFlow_sap(S,T,N+M+4);


        printf("Case %d: ",cas++);
        if(f==(N+M)*L) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

假算法 分析:贪心地删边后检查每个点的度即可,居然能过?

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e4+5;
struct Edge{
    int u,v,next;
}edges[MAXN<<2];
int head[MAXN],tot;
int deg[MAXN];

void init()
{
    memset(head,-1,sizeof(head));
    tot =0 ;
    memset(deg,0,sizeof(deg));
}

void AddEdge(int u,int v)
{
    edges[tot] = (Edge){u,v,head[u]};
    head[u] = tot++;
}

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int cas = 1;
    int N,M,K,u,v;
    while(scanf("%d %d %d",&N,&M,&K)==3){
        init();
        memset(deg,0,sizeof(deg));
        int L,R; scanf("%d %d",&L, &R);

        for(int i=1;i<=K;++i){
            scanf("%d %d",&u,&v);
            v+=N;
            AddEdge(u,v);
            deg[u]++;  deg[v]++;
        }

        for(int e=0;e<tot;++e){
            u = edges[e].u, v =edges[e].v;
            if(deg[u]>R || deg[v]>R){
                deg[u]--;
                deg[v]--;
            }
        }

        bool flag = true;

        for(int i=1;i<=N+M;++i){
            if(deg[i]<L || deg[i]>R){
                flag = false;
                break;
            }
        }
        printf("Case %d: ",cas++);
        if(flag) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部