题目来源:http://poj.org/problem?id=2679
题目描述:
给你一个很复杂的图(输入很蛋疼。。。),每条路径有两个权值(fee,length),让你求某两个点之间fee值最短的路径,如果存在两条最短路则选择length值最小的路径。但是还存在某些限制
1、如果这两点之间没有路径则输出VOID
2、如果这两点之间的路径上有负环则输出UNBOUND
3、从某个点去向其他点(包括自己)的路径只能选择fee值最小的。
大体就是这个意思,由于我不想用邻接表写。。所以只能乱搞了一下(因为n^3的算法会超时)。
1、首先判断这两点之间是否存在路径,如果不存在直接输出,并退出;
2、如果存在路径,在判断起始点是否有自连的负环,如果有直接输出UNBOUND;
3、上述两者都满足的条件下,用spfa算法,当有某个点进队n次以上的时候,说明这个点在某个负环上,用dfs判断此点和终点是否有路径,如果有则直接输出UNBOUND,退出,否则,标记该点,不让他在进队,continue。
代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <fstream>
#include <queue>
#define INF 99999999
using namespace std;
struct edge
{
int fee;
int length;
};
edge edges[1101][1101];
bool visited[1101];
int dis[1101];
int count[1101];
bool fff[1101];
int len[1101];
int n,m,first,last;
bool vis[1101];
bool dfs(int a,int b)
{
if(b == a)
return true;
vis[a] = true;
for(int i = 1 ; i <= n ; i++)
{
if(a != i && !vis[i] && edges[a][i].length < INF)
{
vis[i] = true;
if(dfs(i,b))
return true;
}
}
return false;
}
int spfa()
{
for (int i = 1 ; i <= n; i++)//初始化
{
count[i] = 0;
dis[i] = INF;
visited[i] = false;
fff[i] = false;
len[i] = 0;
}
queue<int> Q;
dis[first] = 0;
count[first] = 1;
visited[first] = true;
Q.push(first);
while (!Q.empty())
{
int temp = Q.front();
//cout<<temp<<endl;
Q.pop();
visited[temp] = false;
if(count[temp] > n)
{
//cout<<temp<<endl;
fff[temp] = true;
memset(vis,false,sizeof(vis));
if(dfs(temp,last))
{
//cout<<temp<<' '<<last<<endl;
return -1;//Unbound;
}
else
continue;
}
for (int i = 1 ; i <= n; i++)
{
if (edges[temp][i].length < INF && dis[temp] + edges[temp][i].fee <= dis[i])
{
if(dis[temp] + edges[temp][i].fee < dis[i])
{
len[i] = len[temp] + edges[temp][i].length;
dis[i] = dis[temp] + edges[temp][i].fee;
if (!visited[i] && !fff[temp])
{
Q.push(i);
count[i]++;
visited[i] = true;
}
}
else if(len[temp] + edges[temp][i].length < len[i])
{
len[i] = len[temp] + edges[temp][i].length;
if (!visited[i] && !fff[temp])
{
Q.push(i);
count[i]++;
visited[i] = true;
}
}
}
}
}
if(dis[last] == INF)
return 0;//VOID
else
return 1;
}
int main()
{
int u,v,fuv,fvu,le;
char ch;
while(scanf("%d%d%d%d",&n,&m,&first,&last)!=EOF)
{
first++;
last++;
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= n ; j++)
{
edges[i][j].fee = 0;
edges[i][j].length = INF;
}
for(int i = 1 ; i <= m; i++)
{
scanf(" %c%d%c%d%c%d%c%d%c%d%c",&ch,&u,&ch,&v,&ch,&fuv,&ch,&le,&ch,&fvu,&ch);
if(edges[u + 1][v + 1].length == INF)
{
if(u != v)
{
edges[u + 1][v + 1].fee = fuv;
edges[v + 1][u + 1].fee = fvu;
edges[u + 1][v + 1].length = edges[v + 1][u + 1].length = le;
}
else
{
edges[u + 1][v + 1].fee = fuv < fvu ? fuv : fvu;
edges[u + 1][v + 1].length = edges[v + 1][u + 1].length = le;
}
}
else
{
if(edges[u + 1][v + 1].fee >= fuv)
{
if(edges[u + 1][v + 1].fee > fuv)
{
edges[u + 1][v + 1].fee = fuv;
edges[u + 1][v + 1].length = le;
}
else
{
edges[u + 1][v + 1].length = edges[u + 1][v + 1].length < le ? edges[u + 1][v + 1].length : le;
}
}
if(edges[v + 1][u + 1].fee >= fvu)
{
if(edges[v + 1][u + 1].fee > fvu)
{
edges[v + 1][u + 1].fee = fvu;
edges[v + 1][u + 1].length = le;
}
else
{
edges[v + 1][u + 1].length = edges[v + 1][u + 1].length < le ? edges[v + 1][u + 1].length : le;
}
}
}
}
for(int i = 1 ; i <= n; i++)
{
int min = INF;
for(int j = 1 ; j <= n ; j++)
{
if(edges[i][j].length < INF && min > edges[i][j].fee)
min = edges[i][j].fee;
}
if(min != INF)
{
for(int j = 1 ; j <= n ; j++)
{
if(min < edges[i][j].fee)
{
edges[i][j].length = INF;
edges[i][j].fee = 0;
}
}
}
}
memset(vis,false,sizeof(vis));
ofstream out("2679.txt",ios::out);
if(!dfs(first,last))
{
cout<<"VOID\n";
continue;
}
if(edges[first][first].length < INF && edges[first][first].fee < 0)
{
cout<<"UNBOUND\n";
continue;
}
memset(vis,false,sizeof(vis));
int ans = spfa();
if(ans == -1)
cout<<"UNBOUND\n";
else if(ans == 0)
cout<<"VOID\n";
else
cout<<dis[last]<<' '<<len[last]<<endl;
}
return 0;
}