• CF720B Cactusophobia【网络流】


    CF720B

    Description

    给定一棵每条边有颜色的仙人掌,请你删去最少的边使得图中没有环,并在边最少的基础上使剩余边的颜色数尽量多,求剩余的颜色数。

    仙人掌的性质:每条边至多被包含在一个简单环中

    (nle 10000)

    Solution

    根据仙人掌的性质,我们可以将所有简单环提出来分别进行考虑,每条环中需要删去一条边,而其他边都可以保留。

    在删掉所有环的前提下使得剩余颜色数最多,这是一个网络流模型,我们首先强制所有颜色不能被删完,得到还剩余多少个环,那么剩余环的数量就是必须减少的颜色的数量。

    具体的,我们对颜色及环建点,从 (s) 向每个颜色建边,流量为最多能删多少条这样颜色的边,(若有一条不在环上的边为该颜色,那么可以删 (de) 次,否则只能删 (de-1) 次,其中 (de) 为该颜色在所有环中的出现次数)。

    从每个环的所有颜色向其连边,流量为 (1);从每个环向 (t) 连边,流量为 (1)。表明将该环删除需要删除其中至少一条边。然后跑出最大流,总环数 (-) 最大流即为必须减少的颜色数。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    namespace iobuff{
    	const int LEN=1000000;
    	char in[LEN+5],out[LEN+5];
    	char *pin=in,*pout=out,*ed=in,*eout=out+LEN;
    	inline char gc(void){return pin==ed&&(ed=(pin=in)+fread(in,1,LEN,stdin),ed==in)?EOF:*pin++;}
    	template<typename T> inline void read(T &x){
    		static int f;
    		static char c;
    		c=gc(),f=1,x=0;
    		while(c<'0'||c>'9') f=(c=='-'?-1:1),c=gc();
    		while(c>='0'&&c<='9') x=10*x+c-'0',c=gc();
    		x*=f;
    	}
    }
    using namespace iobuff;
    
    #define pb push_back
    const int N=8e5+10,M=N<<1,T=4e5+10;
    const int inf=0x3f3f3f3f;
    struct node{
    	int v,w,nxt;
    }e[M];
    int n,m,co,sum,cnt=1,first[T],d[T],bel[T];
    vector<int> cir[T];
    inline void add(int u,int v,int w){e[++cnt].v=v;e[cnt].w=w;e[cnt].nxt=first[u];first[u]=cnt;}
    bool vis[N],tp[T],pd[T];
    int pos[N],pred[N],col[T],de[T];
    inline void dfs(int u){
    	tp[u]=1;vis[u]=1;
    	for(int i=first[u];i;i=e[i].nxt){
    		if(bel[i>>1]||i==(pos[u]^1)) continue;
    		int v=e[i].v;
    		if(tp[v]){
    			++sum;cir[sum].pb(e[i].w);bel[i>>1]=sum;
    			int now=u;
    			while(now!=v){
    				cir[sum].pb(e[pos[now]].w),bel[pos[now]>>1]=sum;
    				now=pred[now];
    			}
    		}
    		else pos[v]=i,pred[v]=u,dfs(v); 
    	}
    	tp[u]=0;
    }
    
    int s,t;
    namespace flow{
    	int tot,dis[N],cur[N];
    	struct edge{
    		int v,f,nxt;
    	}e[M];
    	inline void add(int u,int v,int f){e[++cnt]=(edge){v,f,first[u]};first[u]=cnt;}
    	inline void Add(int u,int v,int f){add(u,v,f);add(v,u,0);}
    	inline int bfs(){
    		memset(dis+1,-1,sizeof(int)*(tot));
    		queue<int>q;
    		dis[s]=0;q.push(s);
    		while(!q.empty()){
    			int u=q.front();q.pop();
    			for(int i=first[u];i;i=e[i].nxt){
    				int v=e[i].v;
    				if(e[i].f>0&&dis[v]==-1){
    					dis[v]=dis[u]+1;
    					q.push(v);
    					if(v==t) return 1;
    				}
    			}
    		}
    		return 0;
    	}
    	inline int dfs(int u,int f){
    		if(u==t||f==0) return f;
    		int used=0;
    		for(int& i=cur[u];i;i=e[i].nxt){
    			if(e[i].f>0&&dis[e[i].v]==dis[u]+1){
    				int w=dfs(e[i].v,min(f,e[i].f));
    				if(!w) continue;
    				used+=w;
    				f-=w;e[i].f-=w;e[i^1].f+=w;
    				if(!f) break;
    			}
    		}
    		if(!used) dis[u]=-1;
    		return used;
    	}
    	inline int dinic(){
    		int f=0;
    		while(bfs()){
    			memcpy(cur,first,sizeof(int)*(tot+1));
    			f+=dfs(s,inf);	
    		}
    		return f;
    	}
    }
    using flow::tot;
    using flow::Add;
    
    int main(){
    	read(n);read(m);
    	for(int i=1,u,v,w;i<=m;++i){
    		read(u);read(v);read(w);
    		add(u,v,w);add(v,u,w);d[i]=w;
    	}
    	sort(d+1,d+m+1);
    	
    	co=unique(d+1,d+m+1)-d-1;
    	for(int i=2;i<=cnt;i+=2) e[i].w=e[i+1].w=lower_bound(d+1,d+co+1,e[i].w)-d;
    	for(int i=1;i<=n;++i) if(!vis[i]) dfs(i);
    	for(int i=2;i<=cnt;i+=2) if(!bel[i>>1]) pd[e[i].w]=true; 
    	
    	vector<int> ve;
    	for(int i=1;i<=sum;++i){
    		bool flag=false;
    		for(int j:cir[i]){
    			col[j]++;
    			if(col[j]!=1||pd[j]) flag=true;
    		}
    		if(flag){for(int j:cir[i]) pd[j]=true;}
    		else{
    			for(int j:cir[i]) de[j]++;
    			ve.push_back(i);
    		}
    		for(int j:cir[i]) col[j]--;
    	}
    	
    	for(int i=1;i<=co;++i){
    		if(!de[i]) continue;
    		d[i]=++tot;
    	}
    	int now=tot+1;
    	tot+=ve.size();s=++tot;t=++tot;
    	for(int i=1;i<=co;++i){
    		if(!de[i]) continue;
    		if(pd[i]) Add(s,d[i],de[i]);
    		else if(de[i]>1) Add(s,d[i],de[i]-1);
    	}
    	for(int i=0;i<ve.size();++i){
    		int u=ve[i];
    		for(int j:cir[u]) Add(d[j],i+now,1);
    		Add(i+now,t,1);
    	}
    	printf("%d
    ",co-(ve.size()-flow::dinic()));
    //	cerr<<(double)clock()/CLOCKS_PER_SEC<<endl;
    	return 0;
    }
    
  • 相关阅读:
    网络存储——数据保护:RAID
    网络存储——磁盘驱动部件
    操作系统——Linux内核完全注释011c-3.0
    信号量和互斥锁的区别
    svn安装和使用
    putty安装和使用
    linux SVN命令
    eclipse 安装配置
    宏定义中#和##的使用
    线程间通信
  • 原文地址:https://www.cnblogs.com/tqxboomzero/p/14845019.html
Copyright © 2020-2023  润新知