2010 ICPC国内予選 E.最強の呪文
問題概要
辺に英小文字からなる呪文が書かれた有向グラフがある。
スタートからゴールまでグラフを辿ったときに得られる、「それまでにたどった辺の呪文を並べた」文字列のうち、辞書順で最も先頭に来るものを最強の呪文と呼ぶ。
最強の呪文が一意に決まる場合それを、決まらない場合"NO"を出力せよ。
(あ、なんか要約が適当……)
解法
長さが一定なら、呪文の強さは一意に定まる。
したがって、それぞれのノードにたどり着いた時点で、長さがL(0≦L≦500くらいまで)の最強の呪文を全て覚えながらダイクストラ法。
呪文の長さが長かったらループしているので、500字くらいで適当に打ち切ってよい。
そもそもゴールにたどり着けない場合および、ゴールに着いた時の呪文が長すぎる場合は、最強の呪文が決定できないときなので"NO"を出力する。
ソースコード
AOJで1.3secくらいでAC.
int n,a,s,g; vector<vector<pair<int,string> > > e; string dp[40][500]; struct Node{ string str; int cur; Node(int a,string b):cur(a),str(b){} Node(){} bool operator<(const Node &r)const{ return str>r.str; } }; int main(){ while(cin>>n>>a>>s>>g,n) { e.clear(); e.resize(n); rep(i,a) { string str; int x,y; cin>>x>>y>>str; e[x].push_back(mp(y,str)); } rep(i,n)rep(j,500)dp[i][j]=""; priority_queue<Node> Q; Q.push(Node(s,"")); while(!Q.empty()) { int cur=Q.top().cur; string cstr=Q.top().str; Q.pop(); if(cstr.size()>=500)continue; if(cur==g) { if(cstr.size()>=400)goto FAIL; cout<<cstr<<endl; goto END; } fr(i,e[cur]) { int nxt=i->first; string nstr=cstr+i->second; if(nstr.size()>=500)continue; if(dp[nxt][nstr.size()]!=""&&dp[nxt][nstr.size()]<=nstr)continue; dp[nxt][nstr.size()]=nstr; Q.push(Node(nxt,nstr)); } } FAIL:cout<<"NO"<<endl; END:; } return 0; }