题意:给出一个带有n个节点和m条单向路径的图,保证图里没有回环,从s点出发,找到一条路径的终点的属性为‘P’,并且路径的长度要能够整除k。
注意:路径要找最短的,如果有不止一条最短路径,那就选择终点编号最小的。
思路:用BFS和DFS都可以做,但剪枝的方法是一样的,用一个1000*1000的数组来保存当在节点i时已走距离j模上k的最小值,即min[i][j%k],当已走距离大于min[i][j%k]时就可以返回。
这题的时间卡的非常紧,用DFS写时写成:
void DFS(){
if(剪枝 == true) return;
for(i=0;i<size;i++) DFS();
}
就会超时,应写成:
void DFS(){
for(i=0;i<size;i++){
if(剪枝 != true) DFS();
}
}
才不会超时,因为函数的递归也要时间,而下面这种写法则省去了大量剪枝时递归的时间。
#include <iostream>
#include <vector>
#include <stdio.h>
#include <string.h>
using namespace std;
struct node{
int x,y;
};
int n,k,pos,MIN;
vector<node> map[1005];
char jer[1005],f;
int F[1005][1005];
void DFS(int now,int v){
if(jer[now] == 'P' && v%k == 0){
if(v<MIN || MIN==-1){
MIN = v;
pos = now;
f = 0;
}
else if(v==MIN && now<pos) pos = now;
return;
}
int size = map[now].size();
for(int i=0;i<size;i++){
int noww = map[now].at(i).x;
int vv = v+map[now].at(i).y;
if(F[noww][vv%k]==-1 || vv<F[noww][vv%k]){
F[noww][vv%k] = v;
DFS(noww,vv);
}
}
}
int main(){
node temp;
int m,s,T,t,i,a,b,c;
scanf("%d",&t);
T = t;
while(t--){
scanf("%d%d%d%d%s",&n,&m,&s,&k,&jer[1]);
for(i=0;i<=n;i++) map[i].clear();
for(i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
temp.x = b;
temp.y = c;
map[a].push_back(temp);
}
memset(F,-1,sizeof(F));
MIN = -1;
f = 1;
DFS(s,0);
printf("Case %d: ",T-t);
if(f) printf("-1 -1\n");
else printf("%d %d\n",MIN,pos);
}
return 0;
}