题目描述
Input
2 3 3 1 1 2 2 1 3 4 2 3 1 3 1 3 3 2 1 1 2 3 2 3 4 3 1 8
Output
NO YES
思路:块田就是图中的点,其中路径是双向的,虫洞是单向的.题目的要求是看能不能找到回到起点时,时间在出发时间之前.
主要还是判断图中有没有负环,并且在回到自己起点时,时间是不是负的.
可以使用Bellman-Ford或者SPFA.
举例:
1.如下图,FJ返回1号时,正好为0.不满足题意.
两种方法的代码如下:
代码:Bellman-Ford
#include<iostream> #include<string.h> using namespace std; int n,m,W; const int maxn = 510; const int INF = 0x3f3f3f3f; int u[maxn],v[maxn],w[maxn],dis[maxn],flag,num; void add(int u1,int v1,int w1){ u[num] = u1; v[num] = v1; w[num] = w1; num++; } bool Ford(int s){ for(int i = 1; i <=n ;i++){ dis[i] = INF; } dis[s] = 0; for(int i = 0; i < n-1; i++){ flag = 0; for(int j = 0; j < num; j++){ if(dis[v[j]]>dis[u[j]]+w[j]){ dis[v[j]] = dis[u[j]] + w[j]; flag = 1; } } if(!flag){ break;//不存在负环 } } for(int j = 0; j < num; j++){ if(dis[v[j]]>dis[u[j]]+w[j]){ //dis[v[j]] = dis[u[j]] + w[j]; return true; } } return false; } int main() { int T,uu,vv,ww; cin>>T; while(T--){ num = 0; cin>>n>>m>>W; for(int i = 0; i < m; i++){ cin>>uu>>vv>>ww; add(uu,vv,ww); add(vv,uu,ww); } for(int i = 0; i < W; i++){ cin>>uu>>vv>>ww; add(uu,vv,-ww); } if(Ford(1)){ cout<<"YES"<<endl; }else{ cout<<"NO"<<endl; } } }
SPFA
#include<iostream> #include<queue> #include<string.h> using namespace std; int n,m,W,num; const int maxn = 510,maxe=6000; const int INF = 0x3f3f3f3f; int head[maxn],vis[maxn],dis[maxn],sum[maxn]; struct Edge { int next,to,w; } e[maxe]; void add(int u,int v,int w) { e[++num].next = head[u]; e[num].to = v; e[num].w = w; head[u] = num; } bool spfa(int u) { queue<int> q; memset(vis,0,sizeof(vis)); memset(sum,0,sizeof(sum)); dis[u] = 0; sum[u]++; q.push(u); vis[u] = 1; while(!q.empty()) { int x = q.front(); q.pop(); vis[x] = 0; for(int i = head[x]; i; i = e[i].next) { int v = e[i].to; if(dis[e[i].to] > dis[x]+e[i].w) { dis[e[i].to] = dis[x]+e[i].w; if(!vis[e[i].to]) { //判断是否在队列内,如果不再就让sum进行++,说明改点又被松弛了一次. sum[e[i].to]++; q.push(e[i].to); vis[e[i].to] = 1; if(sum[e[i].to] >= n) { //判断节点松弛次数是否超过了n return true; } } } } } return false; } int main() { int T,u,v,w; cin>>T; while(T--) { cin>>n>>m>>W; num = 0; for(int i = 1; i <= n; i++) { //dis进行初始化 dis[i] = INF; } memset(head,0,sizeof(head)); for(int i = 0; i < m; i++) { cin>>u>>v>>w; add(u,v,w); add(v,u,w); } for(int i = 0; i < W; i++) { cin>>u>>v>>w; add(u,v,-w);//他是一条负边. } if(spfa(1)) {//存在负环 cout<<"YES"<<endl; } else { cout<<"NO"<<endl; } } return 0; }