PAT-Advanced Level-第十章-图

A 1034

问题总结:1.姓名与编号的映射:一开始是想到使用hash或者map的,但是不会实现=.=,
2.每个组的总边权设为该组内的所有通话的长度之和,每个人的点权设为该人参与的通话的长度之和。
3.使用map来作为姓名与编号的映射编号可以从0到numPerson-1,同时使用map来保存其反向的映射,用于从编号还原姓名,由于题目要求最后结果字母序排列,可以使用Map保存结果,因为map正好是以键的升序排列的!
3.使用DFS来遍历每一个连通分量,注意,此题采用了无向图,因此将实际题目转换为图的时候把边的值要加到邻接矩阵的两个对称的地方。另外为了防止回头,在遍历完一条边后将其值置为0,防止重复遍历
以下为书中代码:

#include 
#include 
#include 
#include 
using namespace std;
const int maxn=2010;
const int inf= INT_MAX;

map<string, int> stringToint;
map<int, string> intTostring;
map<string, int> Gang;
int G[maxn][maxn]={0}, weight[maxn]={0};
int n, k, numPerson=0;			//numPerson为总人数,初始化为0以编号 
bool vis[maxn]={false};

void DFS(int v, int &head, int &numMember, int &totalValue) {
	numMember++;
	vis[v]=true;
	if(weight[v]>weight[head]) {
		head=v;
	}
	for(int i=0; i<numPerson; i++) {
		if(G[v][i]>0) {
			totalValue+=G[v][i];
			G[v][i]=G[i][v]=0;		//删除此边,防止回头 
			if(vis[i]==false) {
				DFS(i, head, numMember, totalValue);
			}
		}
	}
}
void DFSTrave() {
	for(int i=0; i<numPerson; i++) {
		if(vis[i]==false) {
			int head=i, numMember=0, totalValue=0;
			DFS(i, head, numMember, totalValue);
			if(numMember>2 && totalValue>k) {
				Gang[intTostring[head]]=numMember;
			} 
		}
	}
}
 
int change(string str) {		//返回姓名对应的编号 
	if(stringToint.find(str)!=stringToint.end()) {
		return stringToint[str];
	} else {
		stringToint[str]=numPerson;
		intTostring[numPerson]=str;
		return numPerson++;
	}
}

int main() {
	int w;
	string str1, str2;
	cin >> n >> k;
	for(int i=0; i<n; i++) {
		cin >> str1 >> str2 >> w;
		int id1=change(str1);
		int id2=change(str2);
		weight[id1]+=w;
		weight[id2]+=w;
		G[id1][id2]+=w;
		G[id2][id1]+=w; 
	}
	DFSTrave();
	cout << Gang.size() << endl;
	map<string, int>::iterator it;;
	for(it=Gang.begin(); it!=Gang.end(); it++) {
		cout << it->first << " " << it->second << endl;
	}
	return 0;
}

A 1076

总结;1.memset的头文件是cstring!!!别忘了
2.注意各变量不要弄错
3.注意将图的方向反向,即设置为Adj[i]—表示i的followers的结点
已通过OJ

#include 
#include 
#include 
#include  
using namespace std;
struct Node{
	int v, level;
};
const int maxv=1010;
int n, l, count=0;
bool inq[maxv]={false};
vector<Node> Adj[maxv];
void BFS(int u, int &count) {
	queue<Node> q;
	Node start;
	start.v=u;
	start.level=0;
	q.push(start);
	inq[start.v]=true;
	while(!q.empty()) {
		Node now=q.front();
		count++;
		q.pop();
		int x=now.v;
		for(int i=0; i<Adj[x].size(); i++) {
			Node next=Adj[x][i];
			next.level=now.level+1;
			if(inq[next.v]==false && next.level<=l) {
				q.push(next);
				inq[next.v]=true;
			}
		}
	}
}

int main() {
	int num, temp;
	scanf("%d%d", &n, &l);
	for(int i=1; i<=n; i++) {
		scanf("%d", &num);
		for(int j=0; j<num; j++) {
			scanf("%d", &temp);
			Node now;
			now.v=i;
			now.level=0;
			Adj[temp].push_back(now);
		}
	}
	int num_query;
	scanf("%d", &num_query);
	for(int i=0; i<num_query; i++) {
		scanf("%d", &temp);
		int count=0;
		memset(inq, false, sizeof(inq));
		BFS(temp, count);
		cout << count-1 << endl;
	}
	return 0;
}

A 1013

总结:1.BFS的邻接矩阵还不太熟,有几个地方写错了调试了五六分钟=.=,
2.根据题目的具体要求,确定对哪些城市初始化,然后再进行搜索
3.注意每次修改了inq[]后要重新初始化
已通过OJ-----BFS

#include 
#include 
#include 
using namespace std;
const int maxv=1010;
int n, m, k, G[maxv][maxv]={0}, G_temp[maxv][maxv]={0};
bool inq[maxv]={false};
void BFS(int u) {
	queue<int> q;
	q.push(u);
	inq[u]=true;
	while(!q.empty()) {
		int now=q.front();
		q.pop();
		for(int i=1; i<=n; i++) {
			if(inq[i]==false && G_temp[now][i]!=0) {
				q.push(i);
				inq[i]=true;
			}
		}
	}
}
void BFSTrave(int temp, int &count) {
	inq[temp]=true;
	for(int i=1; i<=n; i++) {
		if(inq[i]==false) {
			BFS(i);
			count++;
		}
	}
}
void renew(int G[][maxv]) {
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			G_temp[i][j]=G[i][j];
		}
	}
}
int main() {
	int c1, c2, temp;
	scanf("%d%d%d", &n, &m, &k);
	for(int i=0; i<m; i++) {
		scanf("%d%d", &c1, &c2);
		G[c1][c2]=G_temp[c1][c2]=1;
		G[c2][c1]=G_temp[c2][c1]=1;
	}
	for(int i=0; i<k; i++) {
		scanf("%d", &temp);
		int count=0;
		renew(G_temp);
		memset(inq, false, sizeof(inq));
		BFSTrave(temp, count);
		cout << count-1 << endl;
	}
	return 0;
}

已通过OJ—DFS-----注意:通常如果DFS和BFS都能用的话,尽量使用DFS,更简单

#include 
#include 
#include 
using namespace std;
const int maxv=1010;
int n, m, k, count=0;
vector<int> Adj[maxv];
bool vis[maxv]={false};
void DFS(int u) {
	vis[u]=true;
	for(int i=0; i<Adj[u].size(); i++) {
		int next=Adj[u][i];
		if(vis[next]==false) {
			DFS(next);
		}
	}
} 
void DFSTrave(int &count) {
	for(int i=1; i<=n; i++) {
		if(vis[i]==false) {
			DFS(i);
			count++;
		}
	}
}

int main() {
	int c1, c2, temp;
	scanf("%d%d%d", &n, &m, &k);
	for(int i=0; i<m; i++) {
		scanf("%d%d", &c1, &c2);
		Adj[c1].push_back(c2);
		Adj[c2].push_back(c1);
	}
	for(int i=0; i<k; i++) {
		scanf("%d", &temp);
		memset(vis, false, sizeof(vis));
		count=0;
		vis[temp]=true;
		DFSTrave(count);
		cout << count-1 << endl;
	}
	return 0;
}

另外,此题还可以利用并查集来实现
已通过OJ

#include 
#include 
using namespace std;
const int maxn=1010;
vector<int> Adj[maxn];
int n, m, k, father[maxn];
bool isRoot[maxn]={false};
int findfather(int x) {
	int a=x;
	while(x!=father[x]) {
		x=father[x];
	}
	//路径压缩!!! 
	while(a!=father[a]) {
		int z=a;
		a=father[a];
		father[z]=x;
	}
	return x;
}
void unions(int a, int b) {
	int faA=findfather(a);
	int faB=findfather(b);
	if(faA!=faB) {
		father[faA]=faB;
	}
}
void init() {
	for(int i=1; i<maxn; i++) {
		father[i]=i;
		isRoot[i]=false;
	}
}

int main() {
	int c1, c2, temp;
	scanf("%d%d%d", &n, &m, &k);
	for(int i=0; i<m; i++) {
		scanf("%d%d", &c1, &c2);
		Adj[c1].push_back(c2);
		Adj[c2].push_back(c1);
	}
	for(int i=0; i<k; i++) {
		scanf("%d", &temp);
		init();
		isRoot[temp]=true;
		for(int i=1; i<=n; i++) {
			for(int j=0; j<Adj[i].size(); j++) {
				int v=Adj[i][j];
				if(isRoot[i]==false && isRoot[v]==false) {
					unions(i, v);
				}
			}
		}
		//计算连通分量的个数
		int ans=0;
		for(int i=1; i<=n; i++) {
			int fa_i=findfather(i);
			if(isRoot[fa_i]==false) {
				ans++;
				isRoot[fa_i]=true;
			}
		} 
		cout << ans-1 << endl;
	}
	return 0;
}

A 1021

问题总结:1.有两个测试点无法通过,显示答案错误=.=,感觉自己理解的没有问题啊!
暂时还不知道自己写的代码哪里错了,估计是哪里的逻辑有问题导致错误。
以下为自己写的代码:两个测试点没有通过

#include 
#include 
#include 
using namespace std;
const int maxv=10010;
vector<int> Adj[maxv], ans;
bool vis[maxv]={false};
int maxdepth=0, n, counts=0, depth_one=0;
void DFS(int u, int depth) {
	vis[u]=true;
	if(depth>depth_one) {
		depth_one=depth;
	}
	for(int i=0; i<Adj[u].size(); i++) {
		int v=Adj[u][i];
		if(vis[v]==false) {
			DFS(v, depth+1);
		}
	}
}
void DFSTrave() {
	for(int i=1; i<=n; i++) {
		if(vis[i]==false) {
			DFS(i, 1);
			counts++;
		}
	}
}
int main() {
	int a1, a2, temp;
	scanf("%d", &n);
	for(int i=0; i<n-1; i++) {
		scanf("%d%d", &a1, &a2);
		Adj[a1].push_back(a2);
		Adj[a2].push_back(a1);
	}
	DFSTrave();
	if(counts>1) {
		printf("Error: %d components\n", counts);
	} else if(counts==1){
		for(int i=1; i<=n; i++) {
			memset(vis, false, sizeof(vis));
			DFS(i, 1);
			if(depth_one>maxdepth) {
				ans.clear();
				printf("depth_one=%d, maxdepth=%d\n", depth_one, maxdepth);
				maxdepth=depth_one;
				ans.push_back(i);
			} else if(depth_one==maxdepth) {
				ans.push_back(i);
			}
		} 
		for(int i=0; i<ans.size(); i++) {
			printf("%d\n", ans[i]);
		}
	}
	return 0;
}

柳神代码总结:1.思路:首先进行dfs计算连通分量个数,然后判断是否大于一,若是,则直接输出错误,如果等于一,则再次进行两次dfs,第一次是随机选择一个结点进行一次dfs,同时保留这一次遍历最高高度对应的结点,然后从这些结点中选择一个再次进行一次dfs,将这两次得到的结果保留在一个set中,这样刚好可以去重,之后就是打印出来就可以了
以下为柳神代码:
小技巧:1.vector数组除了vector< int > a[maxn],之外,还可以采用vector v;
2.v.resize(n+1)----表示改变当前容器的容量大小。
3.fill(visit, visit+10010, false)----对数组赋值,也可以采用memset赋值,但后者局限性较大,同时速度较快
4.set的用法注意!

#include 
#include 
#include 
#include 
using namespace std;
int n, maxheight=0;
vector<vector<int>> v;
bool visit[10010];		
set<int> s;				//保存答案 
vector<int> temp;
void dfs(int node, int height) {
	if(height>maxheight) {
		temp.clear();
		temp.push_back(node);
		maxheight=height;
	} else if(height==maxheight) {
		temp.push_back(node);
	}
	visit[node]=true;
	for(int i=0; i<v[node].size(); i++) {
		if(visit[v[node][i]]==false) {
			dfs(v[node][i], height+1);
		}
	}
} 

int main() {
	scanf("%d", &n);
	v.resize(n+1);
	int a, b, cnt=0, s1=0;
	for(int i=0; i<n-1; i++) {
		scanf("%d%d", &a, &b);
		v[a].push_back(b);
		v[b].push_back(a);
	}
	for(int i=1; i<=n; i++) {
		if(visit[i]==false) {
			dfs(i,1);
			if(i==1) {
				if(temp.size()!=0) s1=temp[0];
				for(int j=0; j<temp.size(); j++) {
					s.insert(temp[j]);
				}
			}
			cnt++;
		}
	}
	if(cnt>=2) {
		printf("Error: %d components\n", cnt);
	} else {
		temp.clear();
		maxheight=0;
		fill(visit, visit+10010, false);
		dfs(s1, 1);
		for(int i=0; i<temp.size(); i++) {
			s.insert(temp[i]);
		}
		for(auto it=s.begin(); it!=s.end(); it++) {
			printf("%d\n", *it);
		}
	}
	return 0;
}

A 1003

总结;1.对Dijkstra算法还不熟练!!!!

#include 
#include 
using namespace std;
const int maxv=510;
const int inf=1e9;
int n, G[maxv][maxv], dis[maxv], num[maxv];
int weight[maxv], w[maxv]; 
int m, c1, c2;
bool vis[maxv]={false};

void Dijkstra(int s) {
	fill(dis, dis+maxv, inf);
	fill(num, num+maxv, 0);
	fill(w, w+maxv, 0);
	dis[s]=0;
	num[s]=1;
	w[s]=weight[s]; 
	for(int i=0; i<n; i++) {
		int u=-1, mins=inf;
		for(int j=0; j<n; j++) {
			if(vis[j]==false && dis[j]<mins) {
				u=j;
				mins=dis[j];
			}
		}
		if(u==-1) return ;
		vis[u]=true;
		for(int v=0; v<n; v++) {
			if(vis[v]==false && G[u][v]!=inf) {
				if(dis[u]+G[u][v]<dis[v]) {
					dis[v]=dis[u]+G[u][v];
					num[v]=num[u];
					w[v]=w[u]+weight[v];
 				} else if(dis[u]+G[u][v]==dis[v]) {
					num[v]+=num[u];
					if(w[u]+weight[v]>w[v]) {
						w[v]=w[u]+weight[v];
					}
				}
			}
		}
	}
}
int main() {
	int t1, t2, road, ans_num=0;
	fill(G[0], G[0]+maxv*maxv, inf);
	scanf("%d%d%d%d", &n, &m, &c1, &c2);
	for(int i=0; i<n; i++) {
		scanf("%d", &weight[i]);
	}
	for(int i=0; i<m; i++) {
		scanf("%d%d%d", &t1, &t2, &road);
		G[t1][t2]=road;
		G[t2][t1]=road;
	}
	Dijkstra(c1);
	printf("%d %d\n", num[c2], w[c2]);
	return 0;
}

A 1030

已通过OJ,注意此题采用初始的Dijkstra算法即可,如果使用Dijkstra+dfs的话会比较麻烦

#include
#include 
#include 
using namespace std;
const int maxv=510;
const int inf=1e9;
int n, m, st, des;
int G[maxv][maxv], dis[maxv], cost[maxv][maxv], c[maxv], pre[maxv];
bool vis[maxv]={false};

void Dijkstra(int s) {
	fill(dis, dis+maxv, inf);
	fill(c, c+maxv, inf);
	for(int i=0; i<maxv; i++) pre[i]=i;
	c[s]=0;
	dis[s]=0;
	for(int i=0; i<n; i++) {
		int u=-1, mins=inf;
		for(int j=0; j<n; j++) {
			if(vis[j]==false && dis[j]<mins) {
				u=j;
				mins=dis[j];
			}
		}
		if(u==-1) return;
		vis[u]=true;
		for(int v=0; v<n; v++) {
			if(vis[v]==false && G[u][v]!=inf) {
				if(dis[u]+G[u][v]<dis[v]) {
					dis[v]=dis[u]+G[u][v];
					pre[v]=u;
					c[v]=c[u]+cost[u][v];
				} else if(dis[u]+G[u][v]==dis[v] && c[u]+cost[u][v]<c[v]) {
					c[v]=c[u]+cost[u][v];
					pre[v]=u;
				}
			}
		}
	}
}

void DFS(int s) {
	if(s==st) {
		printf("%d ", s);
		return;
	}
	DFS(pre[s]);
	printf("%d ", s);
}

int main() {
	int c1, c2;
	scanf("%d%d%d%d", &n, &m, &st, &des);
	fill(G[0], G[0]+maxv*maxv, inf);
	for(int i=0; i<m; i++) {
		scanf("%d%d", &c1, &c2);
		scanf("%d%d", &G[c1][c2], &cost[c1][c2]);
		G[c2][c1]=G[c1][c2];
		cost[c2][c1]=cost[c1][c2];
	}
	Dijkstra(st);
	DFS(des);
	printf("%d %d\n", dis[des], c[des]);
	return 0;
}

也可以采用Dijkstra+DFS的方法来写,但是对于只有两个标尺的题目,用原来的方法会简单些
以下为代码,已通过OJ

#include 
#include 
#include 
using namespace std;
const int maxv=510;
const int inf=1e9;
int n, m, st, des;
int G[maxv][maxv], dis[maxv], cost[maxv][maxv]; 
bool vis[maxv]={false};
vector<int> pre[maxv];
int optvalue=inf;
vector<int> path, tempPath;

void Dijkstra(int s) {
	fill(dis, dis+maxv, inf);
	dis[s]=0;
	for(int i=0; i<n; i++) {
		int u=-1, mins=inf;
		for(int j=0; j<n; j++) {
			if(vis[j]==false && dis[j]<mins) {
				u=j;
				mins=dis[j];
			}
		}
		if(u==-1) return;
		vis[u]=true;
		for(int v=0; v<n; v++) {
			if(vis[v]==false && G[u][v]!=inf) {
				if(dis[u]+G[u][v]<dis[v]) {
					dis[v]=dis[u]+G[u][v];
					pre[v].clear();
					pre[v].push_back(u);
				} else if(dis[u]+G[u][v]==dis[v]) {
					pre[v].push_back(u);
				}
			}
		}
	}
}

void dfs(int s) {
	if(s==st) {
		tempPath.push_back(s);
		int value=0;
		for(int i=tempPath.size()-1; i>0; i--) {
			int id=tempPath[i], idNext=tempPath[i-1];
			value+=cost[id][idNext];
		}
		if(value<optvalue) {
			path=tempPath;
			optvalue=value;
		}
		tempPath.pop_back();
		return;
	}
	tempPath.push_back(s);
	for(int i=0; i<pre[s].size(); i++) {
		dfs(pre[s][i]);
	}
	tempPath.pop_back();
}
int main() {
	int c1, c2;
	fill(G[0], G[0]+maxv*maxv, inf);
	scanf("%d%d%d%d", &n, &m, &st, &des);
	for(int i=0; i<m; i++) {
		scanf("%d%d", &c1, &c2);
		scanf("%d%d", &G[c1][c2], &cost[c1][c2]);
		G[c2][c1]=G[c1][c2];
		cost[c2][c1]=cost[c1][c2];
	}
	Dijkstra(st);
	dfs(des);
	for(int i=path.size()-1; i>=0; i--) {
		printf("%d ", path[i]);
	}
	printf("%d %d\n", dis[des], optvalue);
	return 0;
}

A 1018

问题总结:1.题目也太长了,在理解题意上还不太行!要注意的几点:如果最短路径有多条,则选择从PBMC携带车辆最少的那条,如果仍然有多条,则选择从目的地回到PBMC带回去的车最少的那条路。注意路上所有的站点在到达目的地的时候已经达到了完美状态,因此返回时不用再考虑放车的问题。
2.注意题目 的站点编号实际上是0~n!!!
3.此题不可以单纯地使用Dijkstra算法解决,必须使用Dijkstra+dfs解决,主要问题在于dfs的写法!
4.考虑在将每个站点的点权读入数组的时候就减去cmax/2,这样便于后面的计算,直接根据该点的正负判断是否需要从起点携带自行车到该点。
5.main函数中不要忘记对G[maxv]maxv]进行初始化

#include 
#include 
#include 
using namespace std;
const int maxv=510;
const int inf=1e9;
int n, m, c, ed, G[maxv][maxv], dis[maxv];
bool vis[maxv]={false};
int weight[maxv], minRemain=inf, minNeed=inf;
vector<int> pre[maxv];
vector<int> path, tempPath;

void Dijkstra(int s) {
	fill(dis, dis+maxv, inf);
	dis[s]=0;
	for(int i=0; i<=n; i++) {
		int u=-1, mins=inf;
		for(int j=0; j<=n; j++) {
			if(vis[j]==false && dis[j]<mins) {
				u=j; 
				mins=dis[j];
			}
		}
		if(u==-1) return;
		vis[u]-=true;
		for(int v=0; v<=n; v++) {
			if(vis[v]==false && G[u][v]!=inf) {
				if(dis[u]+G[u][v]<dis[v]) {
					dis[v]=dis[u]+G[u][v];
					pre[v].clear();
					pre[v].push_back(u);
				} else if(dis[u]+G[u][v]==dis[v]) {
					pre[v].push_back(u);
				}
			}
		}
	}
}
void dfs(int v) {
	if(v==0) {
		tempPath.push_back(v);
		int need=0, remain=0;
		for(int i=tempPath.size()-1; i>=0; i--) {
			int id=tempPath[i];
			if(weight[id]>0) {
				remain+=weight[id];
			} else {
				if(remain>abs(weight[id])) {
					remain-=abs(weight[id]);
				} else {
					need+=abs(weight[id])-remain;
					remain=0;
				}
			}
		}
		if(need<minNeed) {
			minNeed=need;
			minRemain=remain;
			path=tempPath;
		} else if(need==minNeed && remain<minRemain) {
			minRemain=remain;
			path=tempPath;
		}
		tempPath.pop_back();
		return;
	}
	tempPath.push_back(v);
	for(int i=0; i<pre[v].size(); i++) {
		dfs(pre[v][i]);
	}
	tempPath.pop_back();
}

int main() {
	int c1, c2, num=0;
	scanf("%d%d%d%d", &c, &n, &ed, &m);
	fill(G[0], G[0]+maxv*maxv, inf);
	for(int i=1; i<=n; i++) {
		scanf("%d", &weight[i]);
		weight[i]-=c/2;
	}
	for(int i=0; i<m; i++) {
		scanf("%d%d", &c1, &c2);
		scanf("%d", &G[c1][c2]);
		G[c2][c1]=G[c1][c2];
	}
	Dijkstra(0);
	dfs(ed);
	printf("%d ", minNeed);
	for(int i=path.size()-1; i>=0; i--) {
		printf("%d", path[i]);
		if(i>0) printf("->");
	}
	printf(" %d\n", minRemain);
	return 0;
}

A 1072

问题总结:1.题目要求看不懂!!英语太烂了吧,总是感觉读起来有歧义,然后具体写代码的时候不知道题目要求都不知道怎么写了。
2.题目要求:选出一个加油站使得距离最近的居民房屋尽可能远,且必须保证所有房子都在服务范围内。输出的是应该选择作为加油站的编号、与该加油站最近的居民房的距离及该加油站距离所有房屋的平均距离。如果有多个最近距离相同的解,则选择平均距离最小的,若仍有多个解,则选择序号最小的那个
以下是自己写的代码:
最后一个测试点没有通过,显示段错误,不知道问题在哪里=.=

#include 
#include 
#include 
#include 
using namespace std;
const int maxv=1010;
const int inf=1e9;
int n, m, k, Ds;
int dis[maxv][maxv];
void Floyd() {
	for(int k=1; k<=n+m; k++) {
		for(int i=1; i<=n+m; i++) {
			for(int j=1; j<=n+m; j++) {
				if(dis[i][k]!=inf && dis[k][j]!=inf && dis[i][k]+dis[k][j]<dis[i][j]) {
					dis[i][j]=dis[i][k]+dis[k][j];
				}
			}
		}
	}
}
int strToNum(string s1) {
	int num=0;
	int len=s1.length(), temp=1;
	if(s1[0]=='G') {
		for(int i=1; i<len; i++) {
			num =num*temp+s1[i]-'0';
			temp*=10; 
		}
		num+=n;
	} else if(s1[0]!='G') {
		temp=1;
		for(int i=0; i<len; i++) {
			num=num*temp+s1[i]-'0';
			temp*=10;
		}
	}
	return num;
}
struct node{
	int v;
	double mindis, avedis;
};
bool cmp(node a, node b) {
	if(a.mindis!=b.mindis) return a.mindis>b.mindis;
	else if(a.avedis!=b.avedis) return a.avedis<b.avedis;
	else return a.v<b.v;
}
int main() {
	int c1, c2, total=0, minDistance;
	string s1, s2;
	vector<node> first;		//表示符合能照顾到所有家庭的站
	int  minAve=inf, minIndex;
	scanf("%d%d%d%d", &n, &m, &k, &Ds);
	fill(dis[0], dis[0]+maxv*maxv, inf);
	getchar();
	for(int i=0; i<k; i++) {
		cin >> s1 >> s2;
		c1=strToNum(s1);
		c2=strToNum(s2);
		scanf("%d", &dis[c1][c2]);
		dis[c2][c1]=dis[c1][c2];
	}
	Floyd();
	for(int i=n+1; i<=n+m; i++) {
		total=0;
		minDistance=inf;
		int j;
		for(j=1; j<=n; j++) {
			if(dis[i][j]>Ds) {
				break;
			}
			total+=dis[i][j];
			if(dis[i][j]<minDistance) {
				minDistance=dis[i][j];
			}
		}
		node now;
		now.v=i;
		now.avedis=1.0*total/n;
		now.mindis=minDistance;
		if(j>n) first.push_back(now);
	}
	if(first.size()==0) {
		printf("No Solution\n");
	} else {
		sort(first.begin(), first.end(), cmp);
		printf("G%d\n", first[0].v-n);
		printf("%.1f %.1f\n", first[0].mindis, first[0].avedis);
	}
	return 0;
}

以下为书中代码:

#include 
#include 
#include 
#include  
using namespace std;
const int maxv=1020;
const int inf=1e9;
int n, m, k, Ds, G[maxv][maxv];
int d[maxv];
bool vis[maxv]={false};
void Dijkstra(int s) {
	fill(vis, vis+maxv, false);
	fill(d, d+maxv, inf);
	d[s]=0;
	for(int i=0; i<=n+m; i++) {
		int u=-1, mins=inf;
		for(int j=1; j<=n+m; j++) {
			if(vis[j]==false && d[j]<mins) {
				u=j;
				mins=d[j];
			}
		}
		if(u==-1) return;
		vis[u]=true;
		for(int v=1; v<=n+m; v++) {
			if(vis[v]==false && G[u][v]!=inf) {
				if(d[u]+G[u][v]<d[v]) {
					d[v]=d[u]+G[u][v];
				}
			}
		}
	}
}
int getID(char str[]) {
	int i=0, len=strlen(str), id=0;
	while(i<len) {
		if(str[i]!='G') {
			id=id*10+(str[i]-'0');
		}
		i++;
	}
	if(str[0]=='G') return n+id;
	else return id;
}

int main() {
	scanf("%d%d%d%d", &n, &m, &k, &Ds);
	int u, v, w;
	char c1[5], c2[5];
	fill(G[0], G[0]+maxv*maxv, inf);
	for(int i=0; i<k; i++) {
		scanf("%s %s %d", c1, c2, &w);
		u=getID(c1);
		v=getID(c2);
		G[v][u]=G[u][v]=w;
	}
	double ansDis=-1, ansAvg=inf;
	int ansID=-1;
	for(int i=n+1; i<=n+m; i++) {
		double minDis=inf, avg=0;
		Dijkstra(i);
		for(int j=1; j<=n; j++) {
			if(d[j]>Ds) {
				minDis=-1;
				break;
			}
			if(d[j]<minDis) minDis=d[j];
			avg+=1.0*d[j]/n;
		}
		if(minDis==-1) continue; 
		if(minDis>ansDis) {
			ansID=i;
			ansDis=minDis;
			ansAvg=avg;
		} else if(minDis==ansDis && avg<ansAvg) {
			ansID=i;
			ansAvg=avg;
		}
	}
	if(ansID==-1) printf("No Solution\n");
	else {
		printf("G%d\n", ansID-n);
		printf("%.1f %.1f\n", ansDis, ansAvg);
	}
	return 0;
}

A1087

总结;1.发现在标尺比较多的时候,最好使用Dijkstra+DFS算法,这个方法思路很清晰,且在处理这种问题的时候比较容易写。
2.注意,这种方法还不太熟,多看多记!!!
3.自己第一遍其实写的是只用Dijkstra算法的代码,提交后发现有一个测试点无法通过,自己写的代码又像屎一样,找错误简直难如登天=.=,所以就换了这个方法写了,发现比只用Dijkstra算法简单多了,但是代码长度变长了。
以下为代码:
已通过OJ

#include 
#include 
#include 
#include  
#include 
using namespace std;
const int maxv= 210;
const int inf=1e9;
int n, k, G[maxv][maxv];
int cost[maxv];
int weight[maxv], w[maxv], num[maxv];
bool vis[maxv]={false};
map<string, int> strToNum;
map<int, string> numToStr; 
int number=0;
int num_path=0;
vector<int> pre[maxv];
void Dijkstra(int s) {
	fill(cost, cost+maxv, inf);
	cost[s]=0;
	for(int i=0; i<n; i++) {
		int u=-1, mins=inf;
		for(int j=0; j<n; j++) {
			if(vis[j]==false && cost[j]<mins) {
				u=j;
				mins=cost[j];
			}
		}
		if(u==-1) return;
		vis[u]=true;
		for(int v=0; v<n; v++) {
			if(vis[v]==false && G[u][v]!=inf) {
				if(cost[u]+G[u][v]<cost[v]) {
					cost[v]=cost[u]+G[u][v];
					pre[v].clear();
					pre[v].push_back(u);
				} else if(cost[u]+G[u][v]==cost[v]) {
					pre[v].push_back(u);
				}
			}
		}
	}
}
vector<int> path, tempPath;
int ans_total=-1, ans_ave=-1;
void dfs(int v) {
	if(v==0) {
		num_path++;
		tempPath.push_back(0);
		int total_weight=0, ave_weight=0;
		for(int i=tempPath.size()-1; i>=0; i--) {
			int t=tempPath[i];
			total_weight+=weight[t];
		}
		ave_weight=total_weight/(tempPath.size()-1);
		if(total_weight>ans_total) {
			ans_total=total_weight;
			ans_ave=ave_weight;
			path=tempPath;	
		} else if(total_weight==ans_total && ave_weight>ans_ave) {
			ans_ave=ave_weight;
			path=tempPath;
		}
		tempPath.pop_back();
		return;
	}
	tempPath.push_back(v);
	for(int i=0; i<pre[v].size(); i++) {
		dfs(pre[v][i]);
	}
	tempPath.pop_back();
}
int main() {
	string a, b;
	int dis, c1, c2;
	scanf("%d%d", &n, &k);
	cin >> a;
	strToNum[a]=number;
	numToStr[number]=a;
	weight[0]=0;
	number++;
	fill(G[0], G[0]+maxv*maxv, inf);
	for(int i=1; i<=n-1; i++) {
		cin >> a >> weight[i];
		strToNum[a]=number;
		numToStr[number]=a;
		number++;
	}
	for(int i=0; i<k; i++) {
		cin >> a >> b >> dis;
		c1=strToNum[a];
		c2=strToNum[b];
		G[c1][c2]=G[c2][c1]=dis;
	}
	Dijkstra(0);
	int ed=strToNum["ROM"];
	dfs(ed);
	printf("%d %d %d %d\n", num_path, cost[ed], ans_total, ans_ave);
	for(int i=path.size()-1; i>=0; i--) {
		cout << numToStr[path[i]];
		if(i>0) printf("->");
	}
	return 0;
}

你可能感兴趣的:(算法笔记之PAT_A组习题)