AOJ 1090-Sports Days
問題概要
日本語なので略
解法
まず,KMPパターンマッチングを用いてグラフを単純化する.
スタートとゴールから辿り付ける範囲に負の閉路がある場合は解が-1.
そうで無い場合はベルマンフォードでポテンシャルを求めて,k番目までの最短路を求めるようなダイクストラを行なう.
実装(C++)
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <climits> #include <queue> #include <stack> #include <algorithm> #include <list> #include <vector> #include <set> #include <map> #include <iostream> #include <deque> #include <complex> #include <string> #include <iomanip> #include <sstream> #include <bitset> #include <valarray> #include <iterator> using namespace std; typedef long long int lli; typedef unsigned int uint; typedef unsigned char uchar; typedef unsigned long long ull; #define REP(i,x) for(int i=0;i<(int)(x);i++) #define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++) #define RREP(i,x) for(int i=(x);i>=0;i--) #define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++) const int INF=999999999; struct Edge{ int src,dst,cost; }; typedef vector<Edge> Node; typedef vector<Node> Graph; void add_edge(Graph &G,int src,int dst,int cost){ G[src].push_back((Edge){src,dst,cost}); } Graph reverseGraph(const Graph &G){ Graph ret(G.size()); REP(i,G.size()){ REP(j,G[i].size()){ const Edge &e=G[i][j]; add_edge(ret,e.dst,e.src,e.cost); } } return ret; } int n,m,k; string pattern; int col[100]; Graph in; bool input(){ cin>>n; if(!n)return false; REP(i,n)cin>>col[i]; in=Graph(n); cin>>m; REP(i,m){ int a,b,c; cin>>a>>b>>c; a--;b--; add_edge(in,a,b,c); } cin>>k>>pattern; return true; } //パターンを考慮したグラフを生成 Graph solvePattern(){ int p=pattern.size(); Graph G(n*p+1); //拡張グラフ REP(i,n){ REP(j,p){ REP(k,in[i].size()){ Edge &e=in[i][k]; if(pattern[j]==col[e.dst]+'0'){ if(j+1<p)add_edge(G,i*p+j,e.dst*p+j+1,e.cost); }else{ string tmp=pattern.substr(0,j)+(char)(col[e.dst]+'0'); //一番マッチングするものを選択 RREP(s,tmp.size()){ if(tmp.substr(tmp.size()-s)==pattern.substr(0,s)){ if(s<p)add_edge(G,i*p+j,e.dst*p+s,e.cost); break; } } } } } } // 終点を固定する REP(j,p){ add_edge(G,p*(n-1)+j,n*p,0); } return G; } // ある頂点から行ける頂点を求める vector<bool> canGo(const Graph &G,int src){ vector<bool> ac(G.size()); ac[src]=true; queue<int> que; que.push(src); while(!que.empty()){ int now=que.front();que.pop(); REP(i,G[now].size()){ const Edge &e=G[now][i]; if(ac[e.dst]==false){ ac[e.dst]=true; que.push(e.dst); } } } return ac; } // 不要な辺を消去する Graph removeEdge(const Graph &G,vector<bool> use){ Graph ret(G.size()); REP(i,G.size()){ REP(j,G[i].size()){ const Edge &e=G[i][j]; if(use[e.src]&&use[e.dst]){ add_edge(ret,e.src,e.dst,e.cost); } } } return ret; } //負の辺を含む最短経路 vector<int> shortestPath(const Graph &G,int s){ vector<int> dist(G.size(),INF); dist[s]=0; int count=0; bool update; do{ update=false; if(count++>(int)G.size()+2)return vector<int>(); REP(i,G.size()){ if(dist[i]==INF)continue; REP(j,G[i].size()){ const Edge &e=G[i][j]; if(dist[e.dst]>dist[e.src]+e.cost){ dist[e.dst]=dist[e.src]+e.cost; update=true; } } } }while(update); return dist; } void add_multiset(multiset<int> &s,int number){ s.insert(number); if((int)s.size()>k){ multiset<int>::iterator it=s.end(); it--; s.erase(it); } } int main(){ while(input()){ Graph G=solvePattern(); int start=0; if(col[0]==pattern[0]-'0'){ start=1; if(pattern.size()==1){ cout<<"0 0"<<endl; //スタートに立てない continue; } } // 終点から行ける点を求める vector<bool> fromStart=canGo(G,start); vector<bool> fromGoal=canGo(reverseGraph(G),G.size()-1); vector<bool> route(G.size()); REP(i,G.size()){ route[i]=(fromStart[i]&&fromGoal[i]); } G=removeEdge(G,route); // ベルマンフォードを用いてポテンシャルを求める vector<int> pot=shortestPath(G,start); if(pot.empty()){ //負の閉路有り cout<<-1<<endl; }else{ vector<multiset<int> > d(G.size()); vector<int> &h=pot; REP(i,G.size()){ REP(v,k)d[i].insert(INF); } add_multiset(d[0],start); typedef pair<int,int> P; priority_queue<P,vector<P>,greater<P> > que; que.push(P(0,start)); while(!que.empty()){ P now=que.top();que.pop(); if(now.first>*d[now.second].rbegin())continue; REP(i,G[now.second].size()){ Edge &e=G[now.second][i]; if(*d[e.dst].rbegin()>now.first+e.cost+h[e.src]-h[e.dst]){ add_multiset(d[e.dst],now.first+e.cost+h[e.src]-h[e.dst]); que.push(P(now.first+e.cost+h[e.src]-h[e.dst],e.dst)); } } } int count=0,ans=0; FOR(it,d[G.size()-1]){ if(*it!=INF){ count++; ans+=*it+h[G.size()-1]-h[start]; } } cout<<count<<" "<<ans<<endl; } } }