2269-Traveling Salesman Problem
解法
グラフを圧縮する.
入次数と出次数が1のグラフが連続する部分を探す.
ループしている場合に注意する.
実装(C++)
#include <vector> #include <iostream> #include <algorithm> #include <cstdio> #include <map> #include <queue> #include <cstdlib> using namespace std; typedef long long Weight; typedef pair<int,Weight> P; struct Node{ vector<P> in,out;//入・出 bool compressed;//すでに圧縮されているか int comp_exit;//圧縮されている場合,次の所 int comp_start;//圧縮されている場合,開始地点 int dist_exit;//圧縮されている場合,次の所までの距離 int dist_start;//圧縮されている場合,開始地点までの距離 int node_no; //圧縮されていない場合のノード番号 Node(){compressed=false;} }; const Weight INF=9999999999999999LL; int n,m; Node nodes[100000]; vector<Weight> d[9000]; struct Edge{ int src,dst; Weight weight; Weight flow; Edge(int f,int t,int c):src(f),dst(t),weight(c){} }; struct Node2:public vector<Edge>{ //ここに頂点の情報を記述する }; bool operator<(const Edge &a,const Edge &b){ return a.weight!=b.weight?a.weight<b.weight:a.dst==b.dst?a.src<b.src:a.dst<b.dst; } bool operator>(const Edge &a,const Edge &b){return b<a;} typedef vector<Node2> Graph; typedef vector<vector<Weight> > Matrix; vector<Weight> dijkstra(const Graph &G,int start){ typedef pair<int,Weight> P; vector<Weight> res(G.size(),INF); res[start]=0; priority_queue<P,vector<P>,greater<P> > que; que.push(P(0,start)); while(!que.empty()){ P t=que.top();que.pop(); if(res[t.second]<t.first)continue; for(int i=0;i<(int)G[t.second].size();i++){ Edge e=G[t.second][i]; if(res[e.dst]>res[t.second]+e.weight){ res[e.dst]=res[t.second]+e.weight; que.push(P(res[e.dst],e.dst)); } } } return res; } #define CHECK(k) (nodes[k].compressed==true||nodes[k].in.size()!=1||nodes[k].out.size()!=1) void compress(int v){ if(CHECK(v))return;//圧縮不能 int start_,end; end=v;start_=v; while(1){ if(CHECK(nodes[end].out[0].first))break; end=nodes[end].out[0].first; if(end==v){ cout<<-1<<endl; exit(0); } } while(1){ if(CHECK(nodes[start_].in[0].first))break; start_=nodes[start_].in[0].first; if(start_==v){ cout<<-1<<endl; exit(0); } } if(start_==end)return; v=start_; int L=0; while(1){ nodes[v].compressed=true; nodes[v].comp_exit=end; nodes[v].comp_start=start_; nodes[v].dist_start=L; if(v==end)break; L+=nodes[v].out[0].second; v=nodes[v].out[0].first; } v=start_; while(1){ nodes[v].dist_exit=L-nodes[v].dist_start; if(v==end)break; v=nodes[v].out[0].first; } nodes[start_].out.clear(); nodes[end].in.clear(); nodes[start_].out.push_back(P(end,L)); nodes[end].in.push_back(P(start_,L)); } #undef CHECK Weight min_dist(int s,int e){ //まず両方圧縮されている場合のチェック if(nodes[s].compressed&&nodes[e].compressed){ if(nodes[s].comp_exit==nodes[e].comp_exit){ if(nodes[s].dist_start<nodes[e].dist_start){ return nodes[e].dist_start-nodes[s].dist_start; } } } Weight res=0; if(nodes[s].compressed==true){ res+=nodes[s].dist_exit; s=nodes[s].comp_exit; } if(nodes[e].compressed==true){ res+=nodes[e].dist_start; e=nodes[e].comp_start; } return res+d[nodes[s].node_no][nodes[e].node_no]; } int main() { nodes[0].compressed=true; scanf("%d%d",&n,&m); for(int i=0;i<m;i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); --a;--b; nodes[a].out.push_back(P(b,(Weight)c)); nodes[b].in.push_back(P(a,(Weight)c)); } for(int i=0;i<n;i++){ compress(i); } for(int i=0;i<n;i++){ if(nodes[i].in.empty()||nodes[i].out.empty()){ cout<<-1<<endl; return 0; } } nodes[0].compressed=false; int k=0; for(int i=0;i<n;i++){ if(nodes[i].compressed){ if(nodes[i].comp_exit==i||nodes[i].comp_start==i){ nodes[i].compressed=false; } } nodes[i].node_no=k; k+=nodes[i].compressed==false; } Graph G(k); for(int i=0;i<n;i++){ if(nodes[i].compressed==false){ int q=nodes[i].node_no; for(int j=0;j<(int)nodes[i].out.size();j++){ G[q].push_back(Edge(q,nodes[nodes[i].out[j].first].node_no,nodes[i].out[j].second)); } } } if(k>=9000)exit(-1); for(int i=0;i<n;i++){ if(nodes[i].compressed==false){ d[nodes[i].node_no]=dijkstra(G,nodes[i].node_no); } } Weight res=0; for(int i=0;i<n;i++){ res+=min_dist(i,(i+1)%n); if(min_dist(i,(i+1)%n)>=INF){ cout<<"-1"<<endl; return 0; } } cout<<res<<endl; return 0; }