暑假训练DAY15(并查集,最小生成树)

The Suspects

 UVA - 1197 

并查集模板题,记得维护一下并查集的大小就好

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define int long long
#define endl '\n'
#define sc(x) scanf("%lld",&x)

using namespace std;
int fa[30005];
int cnt[30005];
void init(int n)
{
	for(int i=0;i<n;i++)
	{
		fa[i]=i;
		cnt[i]=1;
	}
}
int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy) return ;
	fa[fx]=fy;//将fx连接到fy上
	cnt[fy]+=cnt[fx]; 
}
int32_t main()
{
	int n,m;
	while(~scanf("%lld%lld",&n,&m)&&n)
	{
		int i;
		init(n);
		int k,j;
		for(i=0;i<m;i++)
		{
			sc(k);
			int a;
			sc(a);
			for(j=0;j<k-1;j++)
			{
				int b;
				sc(b);
				merge(b,a);
			}
		}
		cout<<cnt[find(0)]<<endl;
	}
	return 0;
}

A Bug's Life

 HDU - 1829 

Background 
Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and that they only interact with bugs of the opposite gender. In his experiment, individual bugs and their interactions were easy to identify, because numbers were printed on their backs. 

Problem 
Given a list of bug interactions, decide whether the experiment supports his assumption of two genders with no homosexual bugs or if it contains some bug interactions that falsify it. 

Input

The first line of the input contains the number of scenarios. Each scenario starts with one line giving the number of bugs (at least one, and up to 2000) and the number of interactions (up to 1000000) separated by a single space. In the following lines, each interaction is given in the form of two distinct bug numbers separated by a single space. Bugs are numbered consecutively starting from one.

Output

The output for every scenario is a line containing "Scenario #i:", where i is the number of the scenario starting at 1, followed by one line saying either "No suspicious bugs found!" if the experiment is consistent with his assumption about the bugs' sexual behavior, or "Suspicious bugs found!" if Professor Hopper's assumption is definitely wrong.

Sample Input

2
3 3
1 2
2 3
1 3
4 2
1 2
3 4

Sample Output

Scenario #1:
Suspicious bugs found!

Scenario #2:
No suspicious bugs found!


        
  

Hint

Huge input,scanf is recommended.
        

详细说明见:https://blog.csdn.net/baiyifeifei/article/details/81459624

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define int long long
#define endl '\n'
#define sc(x) scanf("%lld",&x)

using namespace std;
int fa[2005];
int sex[2005];
void init(int n)
{
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
		sex[i]=0;
	}
}
int find(int x)
{
	if(x==fa[x]) return x;
	int t=find(fa[x]);
	sex[x]=(sex[x]+sex[fa[x]])&1;
	return fa[x]=t;
}
int merge(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy) 
	{
		if(sex[x]==sex[y])
		{
			return 0;
		}
		return 1;
	}
	fa[fx]=fy;
	sex[fx]=(sex[x]+sex[y]+1)&1;
	return 1;
}
int32_t main()
{
	int t;
	sc(t);
	int cnt=1;
	while(t--)
	{
		int n,m;
		sc(n),sc(m);
		init(n);
		int ans=1;
		for(int i=0;i<m;i++)
		{
			int a,b;
			sc(a),sc(b);
			if(!merge(a,b)) ans=0;
		}
		printf("Scenario #%lld:\n",cnt++);
		if(!ans) cout<<"Suspicious bugs found!"<<endl;
		else cout<<"No suspicious bugs found!"<<endl;
		printf("\n");
	}
	return 0;
}

食物链

 POJ - 1182 

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述: 
第一种说法是"1 X Y",表示X和Y是同类。 
第二种说法是"2 X Y",表示X吃Y。 
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 
1) 当前的话与前面的某些真的话冲突,就是假话; 
2) 当前的话中X或Y比N大,就是假话; 
3) 当前的话表示X吃X,就是假话。 
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 

Input

第一行是两个整数N和K,以一个空格分隔。 
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 
若D=1,则表示X和Y是同类。 
若D=2,则表示X吃Y。

Output

只有一个整数,表示假话的数目。

Sample Input

100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

Sample Output

3

详细解释见:https://blog.csdn.net/baiyifeifei/article/details/81459722

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define endl '\n'
#define sc(x) scanf("%d",&x)

using namespace std;
int fa[150005];
void init(int n)
{
	for(int i=0;i<n;i++)
	{
		fa[i]=i;
	}
}
int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy)return ;
	fa[fx]=fy;
}
int main()
{
	int n,k,ans;
	scanf("%d%d",&n,&k);
	{
		init(3*n);
		ans=0;
		int x,a,b;
		while(k--)
		{
			sc(x),sc(a),sc(b);
			a--;
			b--;
			if(a<0||a>=n||b<0||b>=n)
			{
				ans++;
				continue;
			}
			if(x==1)
			{
				if(find(a)==find(b+n)||find(a)==find(b+n+n))
				{
					ans++;
					continue;
				}
				else
				{
					merge(a,b);
					merge(a+n,b+n);
					merge(a+n+n,b+n+n);
				}
			}
			else
			{
				if(find(a)==find(b)||find(a)==find(b+2*n))
				{
					ans++;
					continue;
				}
				else
				{
					merge(a,b+n);
					merge(a+n,b+2*n);
					merge(a+2*n,b);
				}
			}
		}
		cout<<ans<<endl;
		
	}
	return 0;
}

X-Plosives

 UVA - 1160 

A secret service developed a new kind of explosive that attain its volatile property only when a specific association of products occurs. Each product is a mix of two different simple compounds, to which we call a binding pair. If N>2, then mixing N different binding pairs containing N simple compounds creates a powerful explosiveFor example, the binding pairs A+B, B+C, A+C (three pairs, three compounds) result in an explosive, while A+B, B+C, A+D (three pairs, four compounds) does not.

 

You are not a secret agent but only a guy in a delivery agency with one dangerous problem: receive binding pairs in sequential order and place them in a cargo ship. However, you must avoid placing in the same room an explosive association. So, after placing a set of pairs, if you receive one pair that might produce an explosion with some of the pairs already in stock, you must refuse it, otherwise, you must accept it.

 

An example. Let’s assume you receive the following sequence: A+B, G+B, D+F, A+E, E+G, F+H. You would accept the first four pairs but then refuse E+G since it would be possible to make the following explosive with the previous pairs: A+B, G+B, A+E, E+G (4 pairs with 4 simple compounds). Finally, you would accept the last pair, F+H.

 

Compute the number of refusals given a sequence of binding pairs.

 

Input

The input will contain several test cases, each of them as described below. Consecutive test cases are separated by a single blank line.

Instead of letters we will use integers to represent compounds. The input contains several lines. Each line (except the last) consists of two integers (each integer lies between 0 and 105) separated by a single space, representing a binding pair. The input ends in a line with the number –1. You may assume that no repeated binding pairs appears in the input.

 

Output

For each test case, a single line with the number of refusals.

 

Sample Input

1 2

3 4

3 5

3 1

2 3

4 1

2 6

6 5

-1

 

Sample Output

3

详细解释见:https://blog.csdn.net/baiyifeifei/article/details/81459855

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define int long long
#define endl '\n'
#define sc(x) scanf("%lld",&x)

using namespace std;
const int size=1e5+5;
int fa[size];
vector<int> u,v;
void init(int n)
{
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
	}
}
int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
int merge(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy) return 1;
	fa[fx]=fy;
	return 0;
} 
int32_t main()
{
	int a,b;
	int n=0;
	int cnt=0;
	while(~sc(a))
	{
		if(a==-1)
		{
			init(n);
			int ans=0;
			for(int i=0;i<u.size();i++)
			{
				ans+=merge(u[i],v[i]);
				//cout<<u[i]<<' '<<v[i]<<endl;
			}
			cout<<ans<<endl;
			u.clear(),v.clear();
			n=0;
			continue;		
		}
		sc(b);
		u.push_back(a),v.push_back(b);
		++cnt;
		int t=max(a,b);
		if(t>n) n=t;
	}
	return 0;
}

Almost Union-Find

 UVA - 11987 

详细解释见:https://blog.csdn.net/baiyifeifei/article/details/81459989

代码:

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int size=1e6+5;
int tot;
int fa[size],id[size],cnt[size],sum[size];
void init(int n)
{
	tot=n+1;
	for(int i=1;i<=n;i++)
	{
		cnt[i]=1;
		sum[i]=i;
		fa[i]=i;
		id[i]=i;
	}
}
int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
	int fx=find(id[x]),fy=find(id[y]);
	if(fx==fy) return;
	cnt[fy]+=cnt[fx];
	sum[fy]+=sum[fx];
	cnt[fx]=0,sum[fx]=0;
	fa[fx]=fy;
}
void move(int x,int y)
{
	int fx=find(id[x]),fy=find(id[y]);
	id[x]=++tot;
	fa[tot]=fy;
	sum[fy]+=x;
	cnt[fy]++;
	sum[fx]-=x;
	cnt[fx]--;	
}
int32_t main()
{
	int n,k;
	while(~scanf("%lld%lld",&n,&k))
	{
		init(n);
		while(k--)
		{
			int op;
			scanf("%lld",&op);
			if(op==1)
			{
				int a,b;
				scanf("%lld%lld",&a,&b);
				merge(a,b);
			}
			if(op==2)
			{
				int a,b;
				scanf("%lld%lld",&a,&b);
				move(a,b);
			}
			if(op==3)
			{
				int x;
				scanf("%lld",&x);
				int fx=find(id[x]);
				cout<<cnt[fx]<<' '<<sum[fx]<<endl;
			}
		}
	}
}

Networking

 UVALive - 2515 

kruskal模板题,不解释。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define int long long
#define endl '\n'
#define sc(x) scanf("%lld",&x)

using namespace std;
struct edge{
	int u,v,w;
	edge(){}
	edge(int _u,int _v,int _w):u(_u),v(_v),w(_w){} 
	friend bool operator<(edge a,edge b)
	{
		return a.w>b.w;
	}
};
int fa[50];
priority_queue<edge> q;
void init(int n)
{
	while(!q.empty()) q.pop();
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
	}
}
int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
int merge(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy) return 0;
	fa[fx]=fy;
	return 1;
}
int32_t main()
{
	int n,k;
	while(cin>>n&&n)
	{
		cin>>k;
		int cnt=0;
		init(n);
		while(k--)
		{
			int u,v,w;
			sc(u),sc(v),sc(w);
			edge E(u,v,w);
			q.push(E);
		}
		int ans=0;
		while(!q.empty())
		{
			edge E=q.top();
			q.pop();
			if(merge(E.u,E.v))
			{
				ans+=E.w;
				if(++cnt==n-1)
				{
					break;
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

Arctic Network

 UVA - 10369 

给出n个点将他们连成最小生成树,给出k个卫星,有了这些卫星就可以无代价地连接一些边。求出在此条件下的最长的边

也就是求出最小生成树的第k小条边

考虑到这个图的边比较多,选择使用prim算法,需要注意的是,先生成的边不一定小,后生成的边也不一定大

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<climits>
#define int long long
#define endl '\n'

using namespace std;
const int inf=LLONG_MAX;
const int size=505;
int loop[size][size];
int vis[size];
int dis[size];
int locx[size];
int locy[size];
int date[size];
int n,k;
int cnt=0;
void prim(int beg)
{
	int ind=beg;
	memset(vis,0,sizeof(vis));
	vis[ind]=1;
	cnt=0;
	for(int i=0;i<n;i++)
	{
		dis[i]=loop[i][ind];
	}
	for(int i=1;i<n;i++)
	{
		int rule=inf;
		for(int j=0;j<n;j++)
		{
			if(!vis[j]&&dis[j]<rule)
			{
				rule=dis[j];
				ind=j;
			}
		}
		date[cnt++]=rule;
		vis[ind]=1;
		for(int j=0;j<n;j++)
		{
			if(!vis[j]&&loop[ind][j]<dis[j])
			{
				dis[j]=loop[ind][j];
			}
		}
	}
}
void pre_solve()
{
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			loop[i][j]=(locx[i]-locx[j])*(locx[i]-locx[j])+(locy[i]-locy[j])*(locy[i]-locy[j]);
		}
	}
}
int32_t main()
{
	int t;
	cin>>t;
	while(t--)
	{
		scanf("%lld%lld",&k,&n);
		for(int i=0;i<n;i++)
		{
			scanf("%lld%lld",&locx[i],&locy[i]);
		}
		pre_solve();
		prim(0);
		sort(date,date+cnt);
		double ans=(double)date[n-k-1];
		printf("%.2f\n",sqrt(ans));
	}
	
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值