解法
H,D,C,Lを適当に数字に置き換えて一つにまとめてしまう。
あとは既に行ったケーキ屋さんの情報をbitで持たせて幅優先するだけ。
微妙にバグったけど察して修正した。
最初ケーキ屋さんの数が100に見えて怖かった。問題文はちゃんと読もう(戒め)
ソース
#include<iostream>
#include<queue>
#include<vector>
#include<string>
#include<cstdlib>
using namespace std;
#define fr first
#define sc second
#define INF ( 1 << 30 )
int m, n, k, d;
int min_cost[110][1 << 6];
vector< int > cal;
typedef pair < int , int > Pi;
typedef pair < int , Pi > Pii;
struct edge{
int to, cost;
edge(){}
edge( int to, int cost): to(to), cost(cost){};
};
vector < edge > info[110];
int java(string& s){
if(s[0] == 'H') return 0; //MyHome
if(s[0] == 'D') return 1; //市役所
if(s[0] == 'C') return atoi(s.substr(1).c_str()) + 1; //ケーキ屋さん
if(s[0] == 'L') return atoi(s.substr(1).c_str()) + m + 1; //ランドマーク
}
int bfs(){
int ret = INF;
fill_n(*min_cost,110*(1<<6),INF);
queue< Pii > que;
que.push(Pii( 0, Pi( 0, (1<<m) - 1)));
min_cost[0][(1<<m)-1] = true;
while(!que.empty()){
Pii p = que.front();
que.pop();
if(p.sc.fr == 1) ret = min( ret, p.fr);
if(min_cost[p.sc.fr][p.sc.sc] < p.fr ) continue;
for(int i = 0 ; i < info[p.sc.fr].size() ; i++ ){
edge e = info[p.sc.fr][i];
int cost = p.fr + e.cost * k, bit = p.sc.sc;
if( e.to >= 2 && e.to < 2 + m ){
if((bit >> (e.to-2)) & 1){
cost -= cal[e.to-2];
bit &= ~(1 << (e.to-2));
}else continue;
}
if( cost < min_cost[e.to][bit] ){
que.push(Pii( cost,Pi( e.to, bit)));
min_cost[e.to][bit] = cost;
}
}
}
return ret;
}
int main(){
while(cin >> m >> n >> k >> d , m){
cal.resize(m);
for(int i = 0 ; i < m ; i++ ){
cin >> cal[i];
}
for(int i = 0 ; i < d ; i++ ){
string s1, s2;
int cost;
cin >> s1 >> s2 >> cost;
info[java(s1)].push_back(edge( java(s2), cost));
info[java(s2)].push_back(edge( java(s1), cost));
}
cout << bfs() << endl;
for(int i = 0 ; i < 110 ; i++ ) info[i].clear();
}
}
0 件のコメント:
コメントを投稿