题意:
给定一个无向图,求一个边权和最小的环
分析:
求最小环可以O(n^3)的Floyd,也可以枚举删边,假设当前删除边(u,v),那么删除后u到v的最短距离dis[u][v] + w[u][v]便是这个环的最小花费,枚举删边+堆优化的dijkrtra,时间复杂度(m*m*logn),这题要剪枝,(1)所求最短路的终点已经出队列,return(2)队列中的最小值大于答案,return(此题这个才是能过的剪枝)
代码:
#include <bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1e4+15;
const int maxm = 8e3+43;
int t,cnt,m,x,y,w,u,v,p,res,head[maxm];
struct edge{
int to,nxt,w;
}e[maxm<<1];
struct cmp{
bool operator()(const pii a,const pii b){
return a.second > b.second;
}
};
map<pii,int> vis;
inline void add(int x,int y,int _w){
e[++cnt].to = y;e[cnt].w = _w;
e[cnt].nxt = head[x];head[x] = cnt;
}
int dis[maxm];
void init(){
vis.clear();
cnt = 0;res = inf;p = 0;
memset(head,0,sizeof(head));
}
void dijkstra(int x,int y){
memset(dis,inf,sizeof(dis));
priority_queue<pii,vector<pii>,cmp> q;
dis[x] = 0;
q.push(pii(x,0));
while(!q.empty()){
pii now = q.top();q.pop();
int uu = now.first;
if(uu == y || now.second > res) return ; //剪枝
if(dis[uu] < now.second) continue;
for(int i = head[uu];i;i = e[i].nxt){
int vv = e[i].to;
if((uu==x&&vv==y)||(uu==y&&vv==x)) continue; //这条边是删除的边
if(dis[vv] > dis[uu]+e[i].w){
dis[vv] = dis[uu] + e[i].w;
q.push(pii(vv,dis[vv]));
}
}
}
}
int main(){
scanf("%d",&t);
for(int Case = 1; Case <= t; ++Case){
init();
scanf("%d",&m);
for(int i = 1;i <= m; ++i){
scanf("%d %d",&x,&y);
if(!vis[pii(x,y)]) u = ++p,vis[pii(x,y)] = u;
else u = vis[pii(x,y)];
scanf("%d %d %d",&x,&y,&w);
if(!vis[pii(x,y)]) v = ++p,vis[pii(x,y)] = v;
else v = vis[pii(x,y)];
add(u,v,w);
add(v,u,w);
}
for(int i = 1;i <= p; ++i){
for(int j = head[i]; j ;j = e[j].nxt){
if(i >= e[j].to) continue;
dijkstra(i,e[j].to);
res = min(res,dis[e[j].to]+e[j].w);
}
}
printf("Case #%d: %d\n",Case,res==inf ? 0:res);
}
return 0;
}