题意:有n块田,之间有m条无向边表示路径,权值表示走过需要花费的时间。有w对虫洞,虫洞是单向的,表示穿越一定时间到过去,并且回到虫洞指向的点,问一个人有没有可能通过虫洞回到某个起点,并且在从这个起点出发之前的时间,因为这样可以看到过去的自己。
解题:判断负圈,模板题。
//记录一下模板
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #include<math.h> #include<string> #include<map> #include<queue> #include<stack> #include<set> #define ll long long #define inf 0x3f3f3f3f using namespace std; int n,m,w; struct node { int to; int val; }; vector<node>e[505]; int num[505]; int d[505]; bool vis[505]; bool spfa() { queue<int>que; que.push(1); d[1]=0; vis[1]=true; num[1]=1; while( que.size() ) { int q=que.front();///q是当前结点 que.pop(); vis[q]=false; int len=e[q].size(); for(int i=0;i<len;i++) { int next=e[q][i].to; int cost=e[q][i].val; if( d[next] > d[q]+cost ) { d[next]=d[q]+cost; if( !vis[next] )///没有入队 { num[next]++; if( num[next]>=n ) return false;///入了这么多次,存在负圈 vis[next]=true;///入队标记 que.push(next); } } } } return true; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&w);///点、边、负边 memset(d,inf,sizeof(d)); memset(num,0,sizeof(num)); memset(vis,false,sizeof(vis)); for(int i=1;i<=n;i++) e[i].clear(); ///正边+负边总数 int a,b,c; for(int i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c);///起点,终点,权值 e[a].push_back({b,c}); e[b].push_back({a,c}); } for(int i=0;i<w;i++) { scanf("%d%d%d",&a,&b,&c); e[a].push_back({b,-c}); } if( spfa() ) printf("NO\n"); else printf("YES\n"); } return 0; }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #include<math.h> #include<string> #include<map> #include<queue> #include<stack> #include<set> #define ll long long #define inf 0x3f3f3f3f using namespace std; struct edge { int from; int to; int val; }; edge e[5555];///无向边*2+有向边 int d[505];///各个点到起点的距离 int n,m,w,cnt; int a,b,c; void add(int x,int y,int z) { e[cnt].from=x; e[cnt].to=y; e[cnt].val=z; cnt++; } bool Bellman_Ford()//贝尔曼福特 { d[1]=0;///把1作为起点 for(int i=0;i<n;i++) { for(int j=0;j<cnt;j++) { if( d[ e[j].from ] > d[ e[j].to ] + e[j].val ) d[ e[j].from ] = d[ e[j].to ] + e[j].val; } } for(int j=0;j<cnt;j++)///第n+1次,还能对边松弛则说明存在负环 { if( d[ e[j].from ] > d[ e[j].to ] + e[j].val ) return false; } return true; } int main() { int t; scanf("%d",&t); while(t--) { memset(d,inf,sizeof(d)); scanf("%d%d%d",&n,&m,&w);///点、边、负边 cnt=0;///正边+负边的总边数 for(int i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c);///无向边 } for(int i=0;i<w;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,-c); } if( Bellman_Ford() ) printf("NO\n"); else printf("YES\n"); } return 0; }