Fantastic Graph 计蒜客

https://nanti.jisuanke.com/t/31447

逆向考虑 先把所有边都加上再删去 并记录度数 以及最小最大度数min max

如果min<l 那肯定是不符题意的 因为这时的度数是每个点所能到达的极限

在min>=l基础上 若max<=r则随便加边都可符合题意

只有min>=l&&max>r是需要搞的 这时将所有点划分成两个部分 A:degree[i]>r B:l<=degree[i]<=r A集合中是连边太多需要删边的点 B集合中是连边数量比较合适可以提供可删边的点 源点向A集合连边 流量为degree[i]-r B集合向汇点连边 流量为degree[i]-r 

至于AB集合之间的连边 先扫一遍所有边 若当前边的左右端点同在A中 就不动这条边 因为A中点本身就符合题意 删这条边就是浪费 若同在B中 就先删掉这条边 因为这样保证跑网络流时的图是一个二分图 dinic跑二分图的网络流的理论复杂度是sqrt(n)*m 相对快一些 若在不同集合 就在网络中加一条从A到B流量为1的边 然后用最大流判定满流

听说是上下界网络流 没学过。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=20010;
const int maxm=50010;
const int N=0x3f3f3f3f;

struct Node
{
    int to;
    int capa;
    int next;
}edge[maxm];

int u[maxn],v[maxn],book[maxm];
int degree[maxn];
int source,sink;
int cnt,n,m,k;
int head[maxn];
int dep[maxn];

void init()
{
    memset(head,-1,sizeof(head));
    memset(degree,0,sizeof(degree));
    cnt=0;
    return;
}

void add(int u,int v,int capa)
{
    edge[cnt].to=v;
    edge[cnt].capa=capa;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].to=u;
    edge[cnt].capa=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
    return;
}

bool bfs()
{
    queue<int> que;
    que.push(source);
    memset(dep,-1,sizeof(dep));
    dep[source]=0;
    while(!que.empty())
    {
        int node=que.front();
        que.pop();
        for(int i=head[node];~i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(edge[i].capa>0&&dep[v]==-1)
            {
                dep[v]=dep[node]+1;
                if(v==sink) return true;
                que.push(v);
            }
        }
    }
    return dep[sink]!=-1;
}

int dfs(int node,int minn)
{
    if(node==sink||minn==0)
    {
        return minn;
    }
    int r=0;
    for(int i=head[node];~i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(dep[v]==dep[node]+1&&edge[i].capa>0)
        {
            int tmp=dfs(v,min(edge[i].capa,minn));
            if(tmp>0)
            {
                edge[i].capa-=tmp;
                edge[i^1].capa+=tmp;
                r+=tmp;
                minn-=tmp;
                if(!minn) break;
            }
        }
    }
    if(!r) dep[node]=-1;
    return r;
}

int dinic()
{
    int maxflow=0;
    while(bfs())
    {
        maxflow+=dfs(source,N);
    }
    return maxflow;
}

int main()
{
    int cas,i,l,r,minn,maxx,res,sum;
    cas=1;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        init();
        scanf("%d%d",&l,&r);
        for(i=1;i<=k;i++)
        {
            scanf("%d%d",&u[i],&v[i]);
            v[i]+=n;
            degree[u[i]]++,degree[v[i]]++;
        }
        minn=N,maxx=0;
        for(i=1;i<=n+m;i++)
        {
            minn=min(minn,degree[i]);
            maxx=max(maxx,degree[i]);
        }
        if(l<=minn)
        {
            if(maxx<=r) printf("Case %d: Yes\n",cas++);
            else
            {
                memset(book,0,sizeof(book));
                for(i=1;i<=k;i++)
                {
                    if(degree[u[i]]>r&&degree[v[i]]>r)
                    {
                        degree[u[i]]--,degree[v[i]]--;
                        book[i]=1;
                    }
                }
                source=0,sink=n+m+1;
                for(i=1;i<=k;i++)
                {
                    if(book[i]==0)
                    {
                        if(degree[u[i]]>r&&degree[v[i]]>l) add(u[i],v[i],1);
                        else if(degree[v[i]]>r&&degree[u[i]]>l) add(v[i],u[i],1);
                    }
                }
                sum=0;
                for(i=1;i<=n+m;i++)
                {
                    if(degree[i]>r)
                    {
                        add(source,i,degree[i]-r);
                        sum+=(degree[i]-r);
                    }
                    else if(degree[i]>l)
                    {
                        add(i,sink,degree[i]-l);
                    }
                }
                res=dinic();
                if(res==sum) printf("Case %d: Yes\n",cas++);
                else printf("Case %d: No\n",cas++);
            }
        }
        else printf("Case %d: No\n",cas++);
    }
    return 0;
}

/*
4 4 10
1 3
1 2
1 3
2 1
2 1
2 1
3 1
3 2
3 3
4 3
4 4

3 3 7
1 1
1 2
2 3
1 3
3 2
3 3
2 1
2 1

1 3 3
1 1
1 1
1 2
1 3
*/

猜你喜欢

转载自blog.csdn.net/sunyutian1998/article/details/82531836