题意:给出一个有向图,问从0出发后能不能重新回到0并且总边权和为负。
思路:以0为起点,用bellman_ford找负环,如果有负环,则说明0能走到负环,然后能再找一条从负环到0的路,则实现要求,因为在负权里可以多走几圈保证总边权为负。如何找有没有从负环到0的路:如果有负环,再跑一遍询问,如果进行松弛,则说明边的起点在负环内或负环能到达的点,把这些点标记,然后再扫一遍原来的边,如果边的起点和终点没标记,则反向建边,求出0能不能到达被标记的点,如果能,则负环能到达0,。反之不能。
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<sstream>
#include<iostream>
#include<cctype>
#include <cmath>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
struct Edge
{
int from, to, cost;
};
vector<Edge> edge;
vector<Edge> newedge;
int dist[1010];
bool vis[1010];
bool Bellman_ford(int n)
{
for(int i=0; i<n; i++) dist[i] = INF;
dist[0] = 0;
for(int i=0; i<n; i++)
{
bool flag = false;
for(unsigned int j=0; j<edge.size(); j++)
{
Edge e = edge[j];
if(dist[e.from] != INF && dist[e.to] > dist[e.from] + e.cost)
{
dist[e.to] = dist[e.from] + e.cost;
flag = true;
}
}
if(i == n-1)
{
if(flag)
continue;
else
return false;
}
}
if(dist[0] < 0)
return true;
memset(vis, 0, sizeof(vis));
{
for(unsigned int j=0; j<edge.size(); j++)
{
Edge e = edge[j];
if(dist[e.to] > dist[e.from] + e.cost)
{
dist[e.to] = dist[e.from] + e.cost;
vis[e.from] = true;
}
}
}
for(unsigned int i=0; i<edge.size(); i++)
{
Edge e = edge[i];
if(!vis[e.from] || !vis[e.to])
{
newedge.push_back((Edge){e.to, e.from, e.cost});
}
}
for(int i=0; i<n; i++) dist[i] = INF;
dist[0] = 0;
for(int i=0; i<n; i++)
{
for(unsigned int j=0; j<newedge.size(); j++)
{
Edge e = newedge[j];
if(dist[e.from] != INF && dist[e.to] > dist[e.from] + e.cost)
{
dist[e.to] = dist[e.from] + e.cost;
}
}
}
for(int i=0; i<n; i++)
{
if(dist[i] < INF && vis[i])
{
return true;
}
}
return false;
}
int main()
{
int t;
scanf("%d", &t);
int ca = 1;
while(t--)
{
int n, m;
scanf("%d%d", &n, &m);
edge.clear();
newedge.clear();
for(int i=0; i<m; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
edge.push_back((Edge){a, b, c});
}
printf("Case #%d: ", ca++);
if(Bellman_ford(n))
printf("possible\n");
else
printf("not possible\n");
}
return 0;
}