AOJ : 1311 - Test Case Tweaking

問題概要

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1311
有向グラフが与えられます。
ノード1からノードNまで、コストC以下で到達するためには、最小でいくつのエッジのコストを書きかえればいいでしょうか。
エッジのコストは、最小で0まで変更することができます。

アルゴリズム

エッジのコストはいくらにでも変更することができるので、明らかに0に変更した方がいい。


次の状態を保持して、ダイクストラ法で解きましょう。

  • 今いるノードの番号
  • 今までコストを0にしたエッジの個数
  • コスト


closedリストは、[100(ノード番号)][1000(0にしたエッジ数)]の大きさにしたいところですが、実は[100][100]で事足ります。
あるノードに行きつくのに、1000個もエッジのコストを0に必要はなく、最大でもノード数の個数分だけ、0にすればいいからです。

プログラム

typedef pair<int,int> P;

class State{
public:
  int id,del,cost; //ノード番号, 0にしたエッジの個数, コスト
  State(){}
  State(int _id,int _del,int _cost){
    id = _id;
    del = _del;
    cost = _cost;
  }

  bool operator<(const State &st)const{
    return cost > st.cost;
  }
};

int n,m,c;
vector<P> t[102];
bool closed[102][102];

int main(void){
  while(scanf("%d%d%d",&n,&m,&c),n||m||c){
    rep(i,n+1) t[i].clear();
    rep(i,m){
      int a,b,c;
      scanf("%d%d%d",&a,&b,&c);
      t[a].push_back(P(b,c));
    }

    priority_queue<State> open;
    open.push(State(1,0,0));
    memset(closed,0,sizeof(closed));

    int ans = INT_MAX;

    while(!open.empty()){
      State st = open.top(); open.pop();
      if(closed[st.id][st.del]) continue;
      closed[st.id][st.del] = true;

      if(st.id == n){
        ans = min(ans,st.del);
        continue;
      }

      rep(i,t[st.id].size()){
        P e = t[st.id][i];
        //エッジのコストを変更しない
        if(st.cost + e.second <= c && !closed[e.first][st.del]){
          open.push(State(e.first,st.del,st.cost+e.second));
        }
        //エッジのコストを0に変更する
        if(st.del+1 <= n && !closed[e.first][st.del+1]){
          open.push(State(e.first,st.del+1,st.cost));
        }
      }
    }

    printf("%d\n",ans);
  }
}