zoukankan      html  css  js  c++  java
  • BZOJ.3624.[APIO2008]免费道路(Kruskal)

    题目链接

    我们发现有些白边是必须加的,有些是多余的。
    那么我们先把所有黑边加进去,然后把必须要加的白边找出来。
    然后Kruskal,把必须要加的白边先加进去,小于K的话再加能加的白边。然后加黑边。
    要求最后是一棵树,没注意,刚开始以为白边还要多判次。

    简便的写法:

    //2464kb	96ms
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 300000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    const int N=2e4+5,M=1e5+5;
    
    int fa[N];
    bool chose[M];
    char IN[MAXIN],*SS=IN,*TT=IN;
    struct Edge
    {
    	int fr,to,val;
    	inline void Print(){
    		printf("%d %d %d
    ",fr,to,val);
    	}
    	bool operator <(const Edge &x)const{
    		return val<x.val;
    	}
    }e[M];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    #define Init() for(int i=1; i<=n; ++i) fa[i]=i
    int Find(int x)
    {
    	return x==fa[x]?x:fa[x]=Find(fa[x]);
    }
    bool Solve(int n,int m,int K)
    {
    	Init();
    	std::sort(e+1,e+1+m);
    	int k=1;
    	for(int i=m,r1,r2; i; --i)
    	{
    		if((r1=Find(e[i].fr))==(r2=Find(e[i].to))) continue;
    		fa[r1]=r2;
    		if(!e[i].val) e[i].val=-1;//mark the white edge
    		if(++k==n) break;
    	}
    	if(k<n) return 0;
    
    	Init();
    	std::sort(e+1,e+1+m);
    	int used=0; k=1;
    	for(int i=1,r1,r2; i<=m; ++i)
    	{
    		if((r1=Find(e[i].fr))==(r2=Find(e[i].to))) continue;
    		if(used<K || e[i].val==1)
    		{
    			fa[r1]=r2, chose[i]=1;
    			if(e[i].val<=0) e[i].val=0, ++used;
    			if(++k==n) break;
    		}
    	}
    	return used==K&&k==n;
    }
    
    int main()
    {
    	int n=read(),m=read(),K=read();
    	for(int i=1; i<=m; ++i) e[i]=(Edge){read(),read(),read()};
    	if(!Solve(n,m,K)) puts("no solution");
    	else for(int i=1; i<=m; ++i) if(chose[i]) e[i].Print();
    
    	return 0;
    }
    

    为了省掉sort闲的没事的写法:

    //2904kb	76ms
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 250000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    const int N=2e4+5,M=1e5+5;
    
    int fa[N];
    bool choseb[M],chosew[M];
    char IN[MAXIN],*SS=IN,*TT=IN;
    struct Edge
    {
    	int fr,to;
    }b[M],w[M];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    #define Init() for(int i=1; i<=n; ++i) fa[i]=i
    int Find(int x)
    {
    	return x==fa[x]?x:fa[x]=Find(fa[x]);
    }
    inline bool Union(int u,int v)
    {
    	if(Find(u)!=Find(v)) {fa[fa[u]]=fa[v]; return 1;}
    	return 0;
    }
    bool Solve(int n,int m,int K,int bt,int wt)
    {
    	if(wt<K) return 0;
    	Init();
    	int k=1;
    	for(int i=1; i<=bt; ++i) if(Union(b[i].fr,b[i].to)&&++k==n) break;
    	if(k<n)
    		for(int i=1; i<=wt; ++i)
    		{
    			if(!Union(w[i].fr,w[i].to)) continue;
    			chosew[i]=1;//mark the white edge
    			if(++k==n) break;
    		}
    	if(k<n) return 0;
    
    	Init();
    	int used=0; k=1;
    	for(int i=1; i<=wt; ++i)
    		if(chosew[i]&&Union(w[i].fr,w[i].to))
    			if(++used, ++k==n) break;
    	if(used>K) return 0;
    	if(k<n&&used<K)
    		for(int i=1; i<=wt; ++i)
    			if(!chosew[i]&&Union(w[i].fr,w[i].to))
    			{
    				chosew[i]=1, ++used, ++k;
    				if(k==n||used==K) break;
    			}
    	if(used<K) return 0;
    	if(k<n)
    		for(int i=1; i<=bt; ++i)
    		{
    			if(!Union(b[i].fr,b[i].to)) continue;
    			choseb[i]=1;
    			if(++k==n) break;
    		}
    	return k==n;
    }
    
    int main()
    {
    	int n=read(),m=read(),K=read(),bt=0,wt=0;
    	for(int i=1,u,v; i<=m; ++i)
    		if(u=read(),v=read(),read()) b[++bt]=(Edge){u,v};
    		else w[++wt]=(Edge){u,v};
    	if(!Solve(n,m,K,bt,wt)) puts("no solution");
    	else
    	{
    		for(int i=1; i<=wt; ++i) if(chosew[i]) printf("%d %d 0
    ",w[i].fr,w[i].to);
    		for(int i=1; i<=bt; ++i) if(choseb[i]) printf("%d %d 1
    ",b[i].fr,b[i].to);
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    提高github下载速度
    小程序兼容问题
    求斐波拉契数列第n位算法优化
    并发编程:ThreadLocal
    MySQL:常见面试题
    2.1语法基础_表达式目录树(EF底层原理的实现)
    ajax发送post请求:
    投资是普通人摆脱阶层固化的唯一靠谱方式
    人脸识别之Python基于OpenCV
    搜索算法“一二”基于VSCode平台C#语言
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9673096.html
Copyright © 2011-2022 走看看