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&°ree[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&°ree[v[i]]>l) add(u[i],v[i],1);
else if(degree[v[i]]>r&°ree[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
*/