一些模板题,都是dijkstra和prim
第一次写博客就复制黏贴实验报告非常抱歉,下次一定好好写。()
以后自己做的题也会写点题解吧 欢迎找我玩~
HDU Today
Time Limit : 15000/5000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 40 Accepted Submission(s) : 2
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
经过锦囊相助,海东集团终于度过了危机,从此,HDU的发展就一直顺风顺水,到了2050年,集团已经相当规模了,据说进入了钱江肉丝经济开发区500强。这时候,XHD夫妇也退居了二线,并在风景秀美的诸暨市浬浦镇陶姚村买了个房子,开始安度晚年了。
这样住了一段时间,徐总对当地的交通还是不太了解。有时很郁闷,想去一个地方又不知道应该乘什么公交车,在什么地方转车,在什么地方下车(其实徐总自己有车,却一定要与民同乐,这就是徐总的性格)。
徐总经常会问蹩脚的英文问路:“Can you help me?”。看着他那迷茫而又无助的眼神,热心的你能帮帮他吗?
请帮助他用最短的时间到达目的地(假设每一路公交车都只在起点站和终点站停,而且随时都会开)。
Input
输入数据有多组,每组的第一行是公交车的总数N(0<=N<=10000);
第二行有徐总的所在地start,他的目的地end;
接着有n行,每行有站名s,站名e,以及从s到e的时间整数t(0<t<100)(每个地名是一个长度不超过30的字符串)。
note:一组数据中地名数不会超过150个。
如果N==-1,表示输入结束。
Output
如果徐总能到达目的地,输出最短的时间;否则,输出“-1”。
Sample Input
6
xiasha westlake
xiasha station 60
xiasha ShoppingCenterofHangZhou 30
station westlake 20
ShoppingCenterofHangZhou supermarket 10
xiasha supermarket 50
supermarket westlake 10
-1
Sample Output
题目的分析
最短路径问题,难点在每个节点的输入不是编号而是字符串形式的地名。
以及没给样例输出
解决方法:用一个map<string,int> ,以地名为键值编号就好啦。STL真好用!
用了优先队列优化的dijkstra
代码
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
int n;
int graph[155][155];
string start,endd;
int dis[105];
bool vis[105];
int main(){
int t,cnt,i;
string s,e;
map<string,int> mapp;
while(1){
cin >> n;
if(n==-1) break;
cin >> start >> endd;
mapp.clear();
memset(graph,INF,sizeof(graph));
cnt=1;
mapp[start]=1;
if(!mapp[endd]) mapp[endd]=++cnt;
while(n--){
cin >> s >> e >> t;
if(!mapp[s]) mapp[s]=++cnt;
if(!mapp[e]) mapp[e]=++cnt;
//cout << s << " " << mapp[s] << endl;
//cout << e << " " << mapp[e] << endl;
graph[mapp[s]][mapp[e]]=graph[mapp[e]][mapp[s]]=t;
}
memset(vis,false,sizeof(vis));
memset(dis,INF,sizeof(dis));
vis[0]=true;
dis[1]=0;
priority_queue<pair<int,int>> q; //(-长度,结点编号)
for(i=2;i<=n;i++){
dis[i]=graph[1][i];
if(dis[i]!=INF){
q.push(make_pair(-dis[i],i));
}
}
q.push(make_pair(-0,1));
while(!vis[mapp[endd]]){
i=0;
while(vis[i]){
i=q.top().second;
q.pop();
}
vis[i]=true;
for(int j=1;j<=cnt;j++){
if(!vis[j] && dis[j]>dis[i]+graph[i][j]){
dis[j]=dis[i]+graph[i][j];
q.push(make_pair(-dis[j],j));
}
}
}
if(dis[mapp[endd]]!=INF) cout << dis[mapp[endd]];
else cout << "-1";
cout << endl;
}
return 0;
}
代码运行情况
美美过了
感想
在做最短路径/最小生成树问题的时候,需要有的一些习惯:
- 是否有重边?
- 是否有负值边/负值圈?(选择不同算法)
- 是否需要输出路径,还是只需要计算路径长度?
- 根据图是稀疏或稠密选择算法(暂时没遇到卡得很严格的题)
- 优化一下总是没错的,多用scanf少用cin总是没错的
畅通工程
Time Limit : 1000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 90 Accepted Submission(s) : 20
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
Sample Input
3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100
Sample Output
3
?
Source
浙大计算机研究生复试上机考试-2007年
题目的分析
最小生成树问题。用prim算法,因为不确定N的大小,还是不用kruskal冒险了(其实是前一题写了dijkstra好改)
代码
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
int main(){
int n,m,i,j,k,visted,ans;
int w[105][105];
int dis[105];
bool vis[105];
while(1){
cin >> n >> m;
if(n==0) break;
memset(w,INF,sizeof(w));
while(n--){
cin >> i >> j >> k;
if(w[j][i]>k) w[i][j]=w[j][i]=k;
}
ans=visted=0;
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
priority_queue<pair<int,int>> q;
dis[1]=0; vis[0]=true;
for(i=2;i<=m;i++){
dis[i]=w[1][i];
if(dis[i]!=INF){
q.push(make_pair(-dis[i],i));
}
}
q.push(make_pair(0,1));
while(!q.empty()){
i=0;
while(vis[i] && (!q.empty())){
i=q.top().second;
q.pop();
}
if(i==0) break;
vis[i]=true;
visted++;
ans+=dis[i];
for(j=2;j<=m;j++){
if((!vis[j]) && dis[j]>w[i][j]){
dis[j]=w[i][j];
q.push(make_pair(-dis[j],j));
}
}
}
if(visted==m) cout << ans << endl;
else cout << "?" << endl;
}
return 0;
}
代码运行情况
美美过了
感想
对Kruskal的应用场景产生怀疑,决定找点相关题目做做。
还是畅通工程
Time Limit : 4000/2000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 40 Accepted Submission(s) : 15
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最小的公路总长度。
Sample Input
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
Sample Output
3
5
Hint
Hint
Huge input, scanf is recommended.
Source
浙大计算机研究生复试上机考试-2006年
题目的分析
还是最小生成树问题。这次说了是稠密图,可能意思是1002要写kruskal吧 TT。
用之前的代码改了一下,还好今天的题目都没有负权边。
注意循环的退出条件,在所有顶点都访问过(visted==m )的时候就可以退出了。
代码
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
int main(){
int n,m,i,j,k,visted,ans;
int w[105][105];
int dis[105];
bool vis[105];
while(1){
cin >> m;
n=m*(m-1)/2;
if(m==0) break;
memset(w,INF,sizeof(w));
while(n--){
//cin >> i >> j >> k;
scanf("%d%d%d",&i,&j,&k);
if(w[j][i]>k) w[i][j]=w[j][i]=k;
}
ans=visted=0;
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
priority_queue<pair<int,int>> q;
dis[1]=0; vis[0]=true;
for(i=2;i<=m;i++){
dis[i]=w[1][i];
if(dis[i]!=INF){
q.push(make_pair(-dis[i],i));
}
}
q.push(make_pair(0,1));
while(!q.empty()){
i=0;
while(vis[i] && (!q.empty())){
i=q.top().second;
q.pop();
}
if(i==0 || visted==m) break;
vis[i]=true;
visted++;
ans+=dis[i];
for(j=2;j<=m;j++){
if((!vis[j]) && dis[j]>w[i][j]){
dis[j]=w[i][j];
q.push(make_pair(-dis[j],j));
}
}
}
/*
cout << visted << endl;
if(visted==m) cout << ans << endl;
else cout << "?" << endl;
*/
cout << ans << endl;
}
return 0;
}
代码运行情况
美美过了
感想
此处空白
最短路
Time Limit : 5000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 114 Accepted Submission(s) : 30
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。
Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
Sample Input
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0
Sample Output
3
2
Source
UESTC 6th Programming Contest Online
题目的分析
最短路径,dijkstra。
代码
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
int main(){
int n,m,i,j,k,visted;
int w[105][105];
int dis[105];
bool vis[105];
while(1){
//cin >> n >> m;
cin >> m >> n;
if(n==0 && m==0) break;
memset(w,INF,sizeof(w));
while(n--){
cin >> i >> j >> k;
if(w[j][i]>k) w[i][j]=w[j][i]=k;
}
visted=0;
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
vis[1]=true;
dis[1]=0;
for(i=2;i<=m;i++){
dis[i]=w[1][i];
}
for(i=2;i<=m;i++){
int min,pos;
min=INF;
for(j=2;j<=m;j++){
if((!vis[j]) && dis[j]<min){
min=dis[j];
pos=j;
}
}
if(min==INF) break;
vis[pos]=true;
if(vis[m]) break;
for(j=2;j<=m;j++){
if((!vis[j]) && dis[j]>dis[pos]+w[pos][j]){
dis[j]=dis[pos]+w[pos][j];
}
}
}
cout << dis[m] << endl;
}
return 0;
}
代码运行情况
美美过了
感想
此处空白
最短路径问题
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 25 Accepted Submission(s) : 1
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
Input
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
Output
输出 一行有两个数, 最短距离及其花费。
Sample Input
3 2
1 2 5 6
2 3 4 5
1 3
0 0
Sample Output
9 11
Source
浙大计算机研究生复试上机考试-2010年
题目的分析
最短路径,dijkstra!好像有同学写floyd,那是必定要超时的。
“长度d和花费p”其实就是主次关键字,在更新dis[]和寻找下一个访问的顶点时注意更新条件就可以了。
然后起点终点并不默认是1和n,复制黏贴的时候要注意
代码
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
int n,m,i,j,d,p,visted,s,t;
int w[1005][1005];
int mm[1005][1005];
int dis[1005],cost[1005];
bool vis[1005];
int main(){
while(1){
//cin >> n >> m;
cin >> m >> n;
if(n==0 && m==0) break;
memset(w,INF,sizeof(w));
memset(mm,INF,sizeof(m));
while(n--){
//cin >> i >> j >> d >> p;
scanf("%d%d%d%d",&i,&j,&d,&p);
if((w[j][i]>d) || (w[j][i]==d && mm[j][i]>p)){
w[i][j]=w[j][i]=d;
mm[i][j]=mm[j][i]=p;
}
}
scanf("%d%d",&s,&t);
visted=0;
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
memset(cost,INF,sizeof(cost));
for(i=1;i<=m;i++){
dis[i]=w[s][i];
cost[i]=mm[s][i];
}
vis[s]=true;
dis[s]=0;
cost[s]=0;
for(i=1;i<=m;i++){
int min,pos,mincost;
mincost=min=INF;
for(j=1;j<=m;j++){
if((!vis[j]) && (dis[j]<min || (dis[j]==min && cost[j]<mincost))){
min=dis[j];
mincost=cost[j];
pos=j;
}
}
if(min==INF) break;
vis[pos]=true;
if(vis[t]) break;
for(j=1;j<=m;j++){
if((!vis[j]) && (dis[j]>dis[pos]+w[pos][j] || (dis[j]==dis[pos]+w[pos][j] && cost[j]>cost[pos]+mm[pos][j]))){
dis[j]=dis[pos]+w[pos][j];
cost[j]=cost[pos]+mm[pos][j];
}
}
}
cout << dis[t] << " " << cost[t] << endl;
}
return 0;
}
代码运行情况
美美过了
感想
细心细心再细心。
最好还是给dijkstra单独写个函数,条件判断单独写一个函数吧,这次全放一起能看明白,下次题目更复杂就不一定了。