算法竞赛入门经典(第2版)-刘汝佳-第十一章例题解题源码(C++语言)(部分)

例题11-2

本题目直接套用Kruskal算法中,使用并查集来判断来判断联通量,另外要注意的是本题目中顶点的编号是从1开始的,所以初始化p的时候要小心。

#include<bits/stdc++.h>
using namespace std;
const int maxm=5000;
const int INF=0x3f3f3f3f;
int u[maxm],v[maxm],w[maxm],r[maxm],p[maxm];
int m,n;
   
int cmp(const int i,const int j){return w[i]<w[j];}//间接排序函数   
int find(int x){ return p[x]==x? x : p[x] = find(p[x]);}  
int solve()//套用Kruskal的解题方式  
{  
    int ans = INF;  
    for(int i=0;i<m;i++) r[i]=i;//初始化边序号   
    sort(r,r+m,cmp);//给边排序  
    for(int L=0;L<m;L++)
	{
		int cnt=n;
		for(int i=1;i<=n;i++) p[i]=i;//初始化并查集 
			for(int R=L;R<m;R++) 
			{
				int e = r[R]; int x = find(u[e]); int y = find(v[e]);  
        		if(x != y)
				{
					p[x]=y;
					if(--cnt==1)
					{
						ans = min(ans,w[r[R]]-w[r[L]]);
						break;
					}
				}  
				
			}
	}   	
    if(ans == INF) ans = -1; 	
    return ans;//返回最小生成树的权值。   
}   
int main()
{
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);
	while(cin>>n>>m&&n)
	{
		for(int i=0;i<m;i++)
		cin>>u[i]>>v[i]>>w[i];
		cout<<solve()<<endl;
	}
	
	return 0;
} 

例题11-4(WA)

本题目直接采用floyd算法求传递闭包就可,只是本题目的输出顺序可能有所要求,导致WA。具体原因还没找到。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 25+2;
int m,n,d[maxn][maxn];
map<string,int> n2id;
map<int,string> id2n;
void solve()
{
	for(int k=0;k<n;k++)  
		for(int i=0;i<n;i++)  
       	 	for(int j=0;j<n;j++)   
            	d[i][j]=d[i][j]||d[i][k]&&d[k][j];  
}
int main()
{
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);	
	int rnd=1;
	while(cin>>n>>m&&n)
	{	
		cout<<"Calling circles for data set "<<rnd++<<":"<<endl;
		n2id.clear();
		id2n.clear();
		int id=0,vis[maxn];
		memset(d,0,sizeof(d));
		for(int i=0;i<n;i++) d[i][i]=1;
		memset(vis,0,sizeof(vis));
		for(int i=0;i<m;i++)
		{
			string s1,s2;
			cin>>s1>>s2;
			if(!n2id.count(s1))
			{
				n2id[s1]=id;
				id2n[id]=s1;
				id++;
			}
			if(!n2id.count(s2))
			{
				n2id[s2]=id;
				id2n[id]=s2;
				id++;
			}
			d[n2id[s1]][n2id[s2]]=1;	
		}
		solve();
		if(m){
		for (int i=0;i<n;i++)
		{
			if(!vis[i])
			{
				cout<<id2n[i];
				vis[i]=1;
				for(int j=0;j<n;j++)
				{
					if(d[i][j]&&d[i][j]==d[j][i]&&!vis[j])
					{
						cout<<", "<<id2n[j];
						vis[j]=1;
					}	
				}
				cout<<endl;	
			}
		}
		cout<<endl;
		}
	}
	
	return 0;
}

例题11-5

本题采用的算法思想也是floyd算法,具体代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100+10;
int m,n,d[maxn][maxn];
void solve()
{
	for(int k=1;k<=n;k++)  
		for(int i=1;i<=n;i++)  
       	 	for(int j=1;j<=n;j++)
				if(d[i][k]!=-1&&d[k][j]!=-1)
				{
					if(d[i][j]==-1)
					{
						d[i][j]=max(d[i][k],d[k][j]);
					}
					else
						d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));  
				}   
            
}
int main()
{
	//freopen("datain.txt","r",stdin);
	//freopen("dataout.txt","w",stdout);	
	int Q,rnd=1;
	while(cin>>n>>m>>Q&&n)
	{	
		if(rnd>1) cout<<endl;
		cout<<"Case #"<<rnd++<<endl;
		memset(d,-1,sizeof(d));
		for(int i=0;i<m;i++)
		{ 	
			int u,v,w;
			cin>>u>>v>>w;
			d[u][v]=w;
			d[v][u]=w;
		}	
		solve();
		for(int i=0;i<Q;i++)
		{ 	
			int u1,v1;
			cin>>u1>>v1;
			if(d[u1][v1]!=-1)
			cout<<d[u1][v1]<<endl;
			else
			cout<<"no path"<<endl;
		}	
		
	}
	
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值