pat题目中处理图的方法通常有两种:dfs和Dijstra
下面看题目:
1018. Public Bike Management (30)
There is a public bike service in Hangzhou City which provides great convenience to the tourists from all over the world. One may rent a bike at any station and return it to any other stations in the city.
The Public Bike Management Center (PBMC) keeps monitoring the real-time capacity of all the stations. A station is said to be in perfect condition if it is exactly half-full. If a station is full or empty, PBMC will collect or send bikes to adjust the condition of that station to perfect. And more, all the stations on the way will be adjusted as well.
When a problem station is reported, PBMC will always choose the shortest path to reach that station. If there are more than one shortest path, the one that requires the least number of bikes sent from PBMC will be chosen.
Figure 1
Figure 1 illustrates an example. The stations are represented by vertices and the roads correspond to the edges. The number on an edge is the time taken to reach one end station from another. The number written inside a vertex S is the current number of bikes stored at S. Given that the maximum capacity of each station is 10. To solve the problem at S3, we have 2 different shortest paths:
PBMC -> S1 -> S3. In this case, 4 bikes must be sent from PBMC, because we can collect 1 bike from S1 and then take 5 bikes to S3, so that both stations will be in perfect conditions.
PBMC -> S2 -> S3. This path requires the same time as path 1, but only 3 bikes sent from PBMC and hence is the one that will be chosen.
Input Specification:
Each input file contains one test case. For each case, the first line contains 4 numbers: Cmax (<= 100), always an even number, is the maximum capacity of each station; N (<= 500), the total number of stations; Sp, the index of the problem station (the stations are numbered from 1 to N, and PBMC is represented by the vertex 0); and M, the number of roads. The second line contains N non-negative numbers Ci (i=1,…N) where each Ci is the current number of bikes at Si respectively. Then M lines follow, each contains 3 numbers: Si, Sj, and Tij which describe the time Tij taken to move betwen stations Si and Sj. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print your results in one line. First output the number of bikes that PBMC must send. Then after one space, output the path in the format: 0->S1->…->Sp. Finally after another space, output the number of bikes that we must take back to PBMC after the condition of Sp is adjusted to perfect.
Note that if such a path is not unique, output the one that requires minimum number of bikes that we must take back to PBMC. The judge’s data guarantee that such a path is unique.
Sample Input:
10 3 3 5
6 7 0
0 1 1
0 2 1
0 3 3
1 3 1
2 3 1
Sample Output:
3 0->2->3 0
题目大意:
由PBMC为不满足条件的站点送自行车,在送的过程中沿路调整,使得沿途的每个站点车辆数都满足Cmax/2,选择最短的路径,当有多条最短路径时,选择要送的车辆最少的那条,当有多条这样的路径时,选择返回车辆最少的那条。
简析:
方法一:用Dijstra统计长度相同的路径,再用dfs计算送最少车辆和返回最少的路径
方法二:直接dfs找到最短的路径,每次找到一条就计算它的send(要发送的车辆)和remain(要返回的车辆),记录下最少的那一条即可!
(想想啊~用djistra的话,路径要解析出来,很麻烦,所以还是方法二的好 ~~)
方法一:
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <iostream>
using namespace std;
#define inf 99999999
int Cmax, N, Sp, M, x, y, z;//M->road
int Cars[502];
int res_index, res_need = inf, res_remain = inf;
int Time[502][502];
std::vector<int> path[502];
bool visited[502];
std::vector<int> res_s;
void dfs(int root, vector<int> s){
if (root == 0){
int remain = 0;
int need = 0;
for (int j = s.size() - 2; j >= 0; j--)
{
remain = Cars[s[j]] + remain;
if (remain >= Cmax){
remain = remain - Cmax;
}
else{
need += Cmax - remain;
remain = 0;
}
}
if (need<res_need){
res_need = need;
res_remain = remain;
res_s = s;
}
else if (need == res_need){
if (remain<res_remain){
res_need = need;
res_remain = remain;
res_s = s;
}
}
return;
}
for (int i = 0; i <path[root].size(); ++i)
{
s.push_back(path[root][i]);
dfs(path[root][i], s);
s.pop_back();
}
}
void Djistra(){
std::vector<int> time(N + 1, inf);
int min = 0;
time[0] = 0;
visited[0] = true;
while (true){
for (int j = 0; j <= N; ++j)
{
if (Time[min][j]<inf && visited[j] == false){
if (time[min] + Time[min][j]<time[j]){
time[j] = time[min] + Time[min][j];
path[j].clear();
path[j].push_back(min);
}
else if (time[min] + Time[min][j] == time[j]){
path[j].push_back(min);
}
}
}
int MIN = inf, MIN_i;
for (int i = 0; i <= N; ++i)
{
if (visited[i] == false){
if (time[i]<MIN){
MIN = time[i];
MIN_i = i;
}
}
}
min = MIN_i;
if (min == Sp)break;
visited[min] = true;
}
vector<int> s;
s.push_back(Sp);
dfs(Sp, s);
}
int main(int argc, char const *argv[])
{
scanf("%d%d%d%d", &Cmax, &N, &Sp, &M);
Cmax = Cmax / 2;
for (int i = 0; i <= N; ++i)
for (int j = 0; j <= N; ++j)
Time[i][j] = inf;
for (int i = 0; i <= N; i++)
visited[i] = false;
for (int i = 1; i <= N; ++i)
scanf("%d", &Cars[i]);
for (int i = 0; i <M; ++i)
{
scanf("%d%d%d", &x, &y, &z);
Time[x][y] = z;
Time[y][x] = z;
}
Djistra();
printf("%d ", res_need);
for (int i = res_s.size() - 1; i >= 0; i--){
if (i != res_s.size() - 1)
printf("->");
printf("%d", res_s[i]);
}
printf(" %d\n", res_remain);
system("pause");
return 0;
}
方法二:
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>
using namespace std;
int Cmax,N,Sp,M,x,y,ti,minremain=99999999,minsend=999999999,MIN=99999999,remain,send;
int bike[502];//minremain与minsend为res路径所对应的remain和send
int timee[502][502];
vector<int> res;
vector<int> v[502];
void dfs(int x,vector<bool> visited,int len,vector<int> path){
if(len>MIN)return;//剪枝了
if(x==Sp){
if(len<MIN){//时间最小的路径。则直接res=path,minremain=remain,minsend=send;
MIN=len;
res=path;
remain=0,send=0;
for (int i = 1; i <path.size(); ++i){ //计算remain,send
if(remain+bike[path[i]]>Cmax){
remain=remain+bike[path[i]]-Cmax;
}
else{
send+=(Cmax-(remain+bike[path[i]]));
remain=0;
}
}
minremain=remain;
minsend=send;
}
else if(len==MIN){//时间相同,比较remain和send
remain=0,send=0;
for (int i = 1; i <path.size(); ++i){ //计算remain,send
if(remain+bike[path[i]]>Cmax){
remain=remain+bike[path[i]]-Cmax;
}
else{
send+=(Cmax-(remain+bike[path[i]]));
remain=0;
}
}
if(send<minsend){
minsend=send;
minremain=remain;
res=path;
}
else if(send==minsend){
if(remain<minremain){
minremain=remain;
res=path;
}
}
}
return;
}
for (int i = 0; i <v[x].size(); ++i){
if(visited[v[x][i]]==false){
path.push_back(v[x][i]);
visited[v[x][i]]=true;
dfs(v[x][i],visited,len+timee[x][v[x][i]],path);
visited[v[x][i]]=false;
path.pop_back();
}
}
}
int main(int argc, char const *argv[])
{
scanf("%d%d%d%d",&Cmax,&N,&Sp,&M);
Cmax/=2;
for (int i = 1; i <=N; ++i)
scanf("%d",&bike[i]);
for (int i = 0; i <M; ++i){
scanf("%d%d%d",&x,&y,&ti);
v[x].push_back(y);
v[y].push_back(x);
timee[x][y]=timee[y][x]=ti;
}
vector<bool> visited(N+1,false);
vector<int> path;
visited[0]=true;
path.push_back(0);
dfs(0,visited,0,path);
path.pop_back();
visited[0]=false;
cout<<minsend<<" ";
for (int j = 0; j <res.size() ; ++j){
if(j!=0)printf("->");
printf("%d",res[j]);
}
cout<<" "<<minremain<<endl;
system("pause");
return 0;
}
1030. Travel Plan (30)
A traveler’s map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.
Input Specification:
Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (<=500) is the number of cities (and hence the cities are numbered from 0 to N-1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:
City1 City2 Distance Cost
where the numbers are all integers no more than 500, and are separated by a space.
Output Specification:
For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.
Sample Input
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
Sample Output
0 2 3 3 40
题目大意:
选取最短路径,有相同的选取花费最少的。
简析:
方法一:dfs,好像剪不剪枝都不超时,剪枝的话只要把当前距离dist大于当前最小距离mindist的路径直接return;就好!
方法二:Dijstra
方法一:dfs
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>
using namespace std;
#define inf 99999999
int N, M, S, D, x, y, co, di;
vector<int> v[502];
int cost[502][502], len[502][502];
int mindist=inf,mincost=inf;
vector<int> res;
void dfs(int x,vector<bool> visited,int dist,int costt,vector<int>path){
if(dist>mindist)return; //剪枝
path.push_back(x);
if(x==D){
if(dist<mindist){
mindist=dist;
mincost=costt;
res=path;
}
else if(dist==mindist){
if(costt<mincost){
mincost=costt;
res=path;
}
}
}
for (int i = 0; i <v[x].size(); ++i){
int j=v[x][i];
if(visited[j]==false){
visited[j]=true;
dfs(j,visited,dist+len[x][j],costt+cost[x][j],path);
visited[j]=false;
}
}
path.pop_back();
}
int main(int argc, char const *argv[]){
scanf("%d%d%d%d", &N, &M, &S, &D);
for (int i = 0; i <M; ++i){
scanf("%d%d%d%d", &x, &y, &di, &co);
v[x].push_back(y);
v[y].push_back(x);
len[x][y] = len[y][x] = di;
cost[x][y] = cost[y][x] = co;
}
vector<int> path;
vector<bool> visited(N,false);
visited[S]=true;
dfs(S,visited,0,0,path);
visited[S]=false;
for (int i = 0;i<res.size();i++){
if(i!=0)printf(" ");
printf("%d",res[i]);
}
printf(" %d %d\n", mindist, mincost);
system("pause");
return 0;
}
方法二:Djjstra
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>
using namespace std;
#define inf 99999999
int N, M, S, D, x, y, co, di;
vector<int> v[502];
int cost[502][502], len[502][502],dist[502], costt[502], path[502];
bool visited[502];
void Dijstra(){
int min = S;
fill(dist, dist + 502, inf);
fill(costt, costt + 502, inf);
fill(path, path + 502,-1);
fill(visited, visited + 502, false);
dist[min] = 0;
costt[min] = 0;
visited[min] = true;
while (true){
for (int i = 0; i <v[min].size(); ++i){
int j = v[min][i];
if (visited[j] == false){
if (dist[min] + len[min][j]<dist[j]){
dist[j] = dist[min] + len[min][j];
costt[j] = costt[min] + cost[min][j];
path[j] = min;
}
else if (dist[min] + len[min][j] == dist[j]){
if (costt[min] + cost[min][j]<costt[j]){
costt[j] = costt[min] + cost[min][j];
path[j] = min;
}
}
}
}
int MIN = inf, MIN_i;
for (int i = 0; i <N; ++i){
if (visited[i] == false && dist[i]<MIN){
MIN = dist[i];
MIN_i = i;
}
}
min = MIN_i;
visited[min] = true;
if (min == D)break;
}
vector<int>res;
int cur=D;
while(cur!=-1){
res.push_back(cur);
cur=path[cur];
}
for (int i = res.size()-1; i>=0;i--){
if(i!=res.size()-1)printf(" ");
printf("%d",res[i]);
}
printf(" %d %d\n", dist[D], costt[D]);
}
int main(int argc, char const *argv[]){
scanf("%d%d%d%d", &N, &M, &S, &D);
for (int i = 0; i <M; ++i){
scanf("%d%d%d%d", &x, &y, &di, &co);
v[x].push_back(y);
v[y].push_back(x);
len[x][y] = len[y][x] = di;
cost[x][y] = cost[y][x] = co;
}
Dijstra();
system("pause");
return 0;
}
1034. Head of a Gang (30)
One way that the police finds the head of a gang is to check people’s phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls made between the two persons. A “Gang” is a cluster of more than 2 persons who are related to each other with total relation weight being greater than a given threshold K. In each gang, the one with maximum total weight is the head. Now given a list of phone calls, you are supposed to find the gangs and the heads.
Input Specification:
Each input file contains one test case. For each case, the first line contains two positive numbers N and K (both less than or equal to 1000), the number of phone calls and the weight threshold, respectively. Then N lines follow, each in the following format:
Name1 Name2 Time
where Name1 and Name2 are the names of people at the two ends of the call, and Time is the length of the call. A name is a string of three capital letters chosen from A-Z. A time length is a positive integer which is no more than 1000 minutes.
Output Specification:
For each test case, first print in a line the total number of gangs. Then for each gang, print in a line the name of the head and the total number of the members. It is guaranteed that the head is unique for each gang. The output must be sorted according to the alphabetical order of the names of the heads.
Sample Input 1:
8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
Sample Output 1:
2
AAA 3
GGG 3
Sample Input 2:
8 70
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
Sample Output 2:
0
简析:dfs求连通集个数,只需把名字映射成int型即可~
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <string>
using namespace std;
struct Node
{
string name;
int num;
Node(string name,int num):name(name),num(num){}
};
std::vector<Node> res;
string a,b;
int N,K,ti,Tatal=0,num=0,resgangs=0,MAXcall=-1,MAX_i;
bool visited[200000];
vector<int> v[20000];
int total[20000];
string name[20000];
int change(string s){
int res=0,ten=1;
for (int i =2; i >=0; i--){
res+=(s[i]-'A')*ten;
ten*=26;
}
return res;
}
void dfs(int x){
if(total[x]>MAXcall){
MAXcall=total[x];
MAX_i=x;
}
num++;
Tatal+=total[x];
for (int i = 0; i <v[x].size(); ++i){
if(visited[v[x][i]]==false){
visited[v[x][i]]=true;
dfs(v[x][i]);
}
}
}
bool cmp(Node a,Node b){
return a.name<b.name;
}
int main(int argc, char const *argv[])
{
cin>>N>>K;
for (int i = 0; i <N; ++i){
cin>>a>>b>>ti;
int ten=1;
int x=change(a),y=change(b);
name[x]=a;
name[y]=b;
v[x].push_back(y);
v[y].push_back(x);
total[x]+=ti;
total[y]+=ti;
}
fill(visited,visited+20000,false);
for (int i = 0; i <20000; ++i){
if(visited[i]==false){
Tatal=0;
num=0;
MAXcall=-1;
visited[i]=true;
dfs(i);
if(num>2&&Tatal/2>K){
res.push_back(Node(name[MAX_i],num));
resgangs++;
}
}
}
sort(res.begin(), res.end(),cmp);
cout<<resgangs<<endl;
for (int i = 0; i <resgangs; ++i)
cout<<res[i].name<<" "<<res[i].num<<endl;
system("pause");
return 0;
}
1111. Online Map (30)
Input our current position and a destination, an online map can recommend several paths. Now your job is to recommend two paths to your user: one is the shortest, and the other is the fastest. It is guaranteed that a path exists for any request.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N (2 <= N <= 500), and M, being the total number of streets intersections on a map, and the number of streets, respectively. Then M lines follow, each describes a street in the format:
V1 V2 one-way length time
where V1 and V2 are the indices (from 0 to N-1) of the two ends of the street; one-way is 1 if the street is one-way from V1 to V2, or 0 if not; length is the length of the street; and time is the time taken to pass the street.
Finally a pair of source and destination is given.
Output Specification:
For each case, first print the shortest path from the source to the destination with distance D in the format:
Distance = D: source -> v1 -> … -> destination
Then in the next line print the fastest path with total time T:
Time = T: source -> w1 -> … -> destination
In case the shortest path is not unique, output the fastest one among the shortest paths, which is guaranteed to be unique. In case the fastest path is not unique, output the one that passes through the fewest intersections, which is guaranteed to be unique.
In case the shortest and the fastest paths are identical, print them in one line in the format:
Distance = D; Time = T: source -> u1 -> … -> destination
Sample Input 1:
10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
3 4 0 3 2
3 9 1 4 1
0 6 0 1 1
7 5 1 2 1
8 5 1 2 1
2 3 0 2 2
2 1 1 1 1
1 3 0 3 1
1 4 0 1 1
9 7 1 3 1
5 1 0 5 2
6 5 1 1 2
3 5
Sample Output 1:
Distance = 6: 3 -> 4 -> 8 -> 5
Time = 3: 3 -> 1 -> 5
Sample Input 2:
7 9
0 4 1 1 1
1 6 1 1 3
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 1 3
3 2 1 1 2
4 5 0 2 2
6 5 1 1 2
3 5
Sample Output 2:
Distance = 3; Time = 4: 3 -> 2 -> 5
简析:
两次使用Dijkstra算法。一次统计最短路径,一次统计最快路径。
#include <iostream>
#include <vector>
#include <stdio.h>
#include <algorithm>
#define inf 99999999
using namespace std;
int N,M,x,y,one,le,ti,S,D,resDist,resTime;
vector<int> v[502];
int length[502][502],Time[502][502];
std::vector<int> Distance,TIME;
void Dijstra1(){
std::vector<bool> visited(N,false);
std::vector<int> dist(N,inf);
std::vector<int> fast(N,inf);
std::vector<int> path(N,-1);
int min=S;
visited[min]=true;
dist[min]=0;
fast[min]=0;
while(true){
for (int i = 0; i <v[min].size(); ++i)
{
int j=v[min][i];
if(visited[j]==false){
if(dist[min]+length[min][j]<dist[j]){
dist[j]=dist[min]+length[min][j];
fast[j]=fast[min]+Time[min][j];
path[j]=min;
}
else if(dist[min]+length[min][j]==dist[j]){
if(fast[min]+Time[min][j]<fast[j]){
fast[j]=fast[min]+Time[min][j];
path[j]=min;
}
}
}
}
int MIN=inf,MIN_i;
for (int i = 0; i <N; ++i)
{
if(visited[i]==false&&dist[i]<MIN){
MIN=dist[i];
MIN_i=i;
}
}
min=MIN_i;
if(min==D)break;
visited[min]=true;
}
int cur=D;
while(cur!=-1){
Distance.push_back(cur);
cur=path[cur];
}
resDist=dist[D];
}
void Dijstra2(){
std::vector<bool> visited(N,false);
std::vector<int> dist(N,inf);
std::vector<int> path(N,-1);
std::vector<int> cnt(N,inf);
int min=S;
visited[min]=true;
dist[min]=0;
cnt[min]=0;
while(true){
for (int i = 0; i <v[min].size(); ++i)
{
int j=v[min][i];
if(visited[j]==false){
if(dist[min]+Time[min][j]<dist[j]){
dist[j]=dist[min]+Time[min][j];
cnt[j]=cnt[min]+1;
path[j]=min;
}
else if(dist[min]+Time[min][j]==dist[j]){
if(cnt[min]+1<cnt[j]){
cnt[j]=cnt[min]+1;
path[j]=min;
}
}
}
}
int MIN=inf,MIN_i;
for (int i = 0; i <N; ++i)
{
if(visited[i]==false&&dist[i]<MIN){
MIN=dist[i];
MIN_i=i;
}
}
min=MIN_i;
if(min==D)break;
visited[min]=true;
}
int cur=D;
while(cur!=-1){
TIME.push_back(cur);
cur=path[cur];
}
resTime=dist[D];
}
int main(int argc, char const *argv[])
{
scanf("%d%d",&N,&M);
for (int i = 0; i <M; ++i)
{
scanf("%d%d%d%d%d",&x,&y,&one,&le,&ti);
v[x].push_back(y);
if(one==0){
v[y].push_back(x);
}
length[x][y]=length[y][x]=le;
Time[x][y]=Time[y][x]=ti;
}
scanf("%d%d",&S,&D);
Dijstra1();
Dijstra2();
if(Distance==TIME){
printf("Distance = %d; Time = %d: ",resDist,resTime);
for (int i = Distance.size()-1;i>=0;i--)
{
if(i!=Distance.size()-1)printf(" -> ");
printf("%d",Distance[i]);
}
}
else{
printf("Distance = %d: ",resDist);
for (int i = Distance.size()-1;i>=0;i--)
{
if(i!=Distance.size()-1)printf(" -> ");
printf("%d",Distance[i]);
}printf("\n");
printf("Time = %d: ",resTime);
for (int i = TIME.size()-1;i>=0;i--)
{
if(i!=TIME.size()-1)printf(" -> ");
printf("%d",TIME[i]);
}
}
system("pause");
return 0;
}
本文针对PAT竞赛中的三道算法题目进行了解析,包括公共自行车管理、旅行计划和帮派头目识别的问题。提供了两种主要的解决思路:Dijkstra算法用于寻找最短路径,DFS(深度优先搜索)用于遍历图结构并解决特定问题。每道题目均附带了详细的代码实现,帮助读者理解算法的具体应用。
403

被折叠的 条评论
为什么被折叠?



