zoukankan      html  css  js  c++  java
  • CF976F Solution

    题目链接

    题解

    因为度数最少为(k),所以与(i)连接且不选的边最多为(deg_i-k)条。将(u)集合中的点与源点、将(v)集合中的点与汇点连接容量为(deg_i-k)(deg_i)(i)号节点的度数)的边,保留原图中的边,容量为(1)。该图最大流未经过的边即为选择的边。不过暴力枚举(k)时间复杂度为(O(nm^2)),无法通过。因此需要从(minDegree)(1)倒叙枚举(k),每次将与源点、汇点相连的边容量(+1),在之前的剩余网络中跑最大流即可。时间复杂度约为(O(nm))

    AC代码

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N=2010,inf=0x3f3f3f3f;
    int fst[2*N],nxt[6*N],v[6*N],w[6*N],id[6*N],cnt=1;
    int in[2*N],d[2*N],n;
    queue<int> q;
    vector<int> ans[N];
    void add(int x,int y,int z,int i)
    {
    	v[++cnt]=y,w[cnt]=z,id[cnt]=i;
    	nxt[cnt]=fst[x],fst[x]=cnt;
    }
    bool bfs()
    {
    	while(!q.empty()) q.pop();
    	memset(d,0,sizeof(d)); 
    	q.push(0); d[0]=1;
    	while(!q.empty())
    	{
    		int x=q.front(); q.pop();
    		for(int i=fst[x];i;i=nxt[i])
    		{
    			int y=v[i];
    			if(d[y] || !w[i]) continue;
    			d[y]=d[x]+1; q.push(y);
    			if(y==n+1) return 1;
    		}
    	}
    	return 0;
    }
    int dinic(int x,int flow)
    {
    	if(x==n+1) return flow;
    	int res=flow,tmp;
    	for(int i=fst[x];i && res;i=nxt[i])
    	{
    		int y=v[i];
    		if(d[y]!=d[x]+1 || !w[i]) continue;
    		tmp=dinic(y,min(res,w[i]));
    		if(!tmp) d[y]=0;
    		w[i]-=tmp,w[i^1]+=tmp,res-=tmp;
    	}
    	return flow-res;
    }
    int main()
    {
    	int n1,n2,m,x,y,mi=inf;
    	scanf("%d%d%d",&n1,&n2,&m); n=n1+n2;
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&x,&y); y+=n1;
    		add(x,y,1,i),add(y,x,0,-1);
    		in[x]++,in[y]++;
    	}
    	for(int i=1;i<=n;i++) mi=min(mi,in[i]);
    	for(int i=1;i<=n1;i++) add(0,i,in[i]-mi-1,-1),add(i,0,0,-1);
    	for(int i=n1+1;i<=n;i++) add(i,n1+n2+1,in[i]-mi-1,-1),add(n1+n2+1,i,0,-1);
    	for(int i=mi;i>=1;i--)
    	{
    		for(int j=cnt-1;j>=cnt-2*n+1;j-=2) w[j]++;
    		while(bfs()) 
    			while(dinic(0,inf));
    		for(int j=1;j<=cnt;j++) 
    			if(id[j]!=-1 && w[j]) ans[i].pb(id[j]);
    	}
    	printf("0
    ");
    	for(int i=1;i<=mi;i++)
    	{
    		int tmp=ans[i].size();
    		printf("%d ",tmp);
    		for(int j=0;j<tmp;j++) printf("%d ",ans[i][j]);
    		printf("
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    如何得到数据绑定的树节点的父节点
    ImageBrush中的图片如何加载到到MemoryStream
    C#中动态加载和卸载DLL
    SetProcessWorkingSetSize减少内存占用
    wpf中如何改变Listbox选中项的颜色
    怎样把Visual Studio与Perforce关联起来
    在WPF里面如何使用FolderBrowserDialog
    关于WPF的ComboBox中Items太多而导致加载过慢的问题(转载)
    得到系统中所有正打开的文件
    把ResourceDictionary保存为文件,从外部xaml文件加载ResourceDictionary
  • 原文地址:https://www.cnblogs.com/violetholmes/p/15152117.html
Copyright © 2011-2022 走看看