【wikioi】2800出前(状圧dp+floyd)
2931 ワード
http://www.wikioi.com/problem/2800/
本題状はわけのわからないtleを押して、(hzwer大神の打ったことによって、彼は1000余りms、私は2000 msになりましたか?)(14.8.7さらに、getnumをscanfに変えるとacできるのですが、これはどんなリズムですか???データに問題がありますか?
明日また来てみましょう.の書き損なったと思う.
本題ではまずfloydで点間の最短を走り終え、状態f[i][j]を設定してアクセス状況がiの場合現在位置する点をjの最小値とし、
f[i][j]=min(f[i-bit(j)][k]+d[k][j],f[i][k]+d[k][j])であり、bit(j)はjの位置のバイナリ表現を表し、d[k][j]はkからjの最短路を表す
テーマ説明Description
外で売っている人がいて、彼の手にはn部の注文があって、彼はn部のものを、それぞれn人の異なる取引先の手に送ります.n個の異なる顧客はそれぞれ1~n個の番号の都市にいる.出前は0番都市を出発して、それからn都市はすべて1回(1都市は何度も歩くことができます)、最後にまた0時(彼の職場)に戻って、最短の時間はいくらですかをお聞きします.現在、任意の2つの都市の直接通路の時間が知られている.
入力記述Input Description
1行目の正の整数n(1<=n<=15)
次は(n+1)*(n+1)のマトリクスで、マトリクスの数はいずれも10000を超えない正の整数です.行列のi行j列は、i−1番目の都市とj−1番目の都市との間の直接通路の時間を表す.もちろん、都市aから都市bへの直接通路時間と都市bから都市aへの直接通路時間は必ずしも同じではなく、つまり道路は一方向である.
出力記述Output Description
正の整数は、最も少ない時間を表します.
サンプル入力Sample Input
サンプル出力Sample Output
8
データ範囲とヒントData Size&Hint
1<=n<=15
本題状はわけのわからないtleを押して、(hzwer大神の打ったことによって、彼は1000余りms、私は2000 msになりましたか?)(14.8.7さらに、getnumをscanfに変えるとacできるのですが、これはどんなリズムですか???データに問題がありますか?
明日また来てみましょう.の書き損なったと思う.
本題ではまずfloydで点間の最短を走り終え、状態f[i][j]を設定してアクセス状況がiの場合現在位置する点をjの最小値とし、
f[i][j]=min(f[i-bit(j)][k]+d[k][j],f[i][k]+d[k][j])であり、bit(j)はjの位置のバイナリ表現を表し、d[k][j]はkからjの最短路を表す
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define read(a) a=getnum()
#define print(a) printf("%d", a)
#define bit(x) (1<<x)
inline int getnum() { int ret=0; char c; int k=1; for(c=getchar(); c<'0' || c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0' && c<='9'; c=getchar()) ret=ret*10+c-'0'; return k*ret; }
const int N=17;
int f[1<<N][N], d[N][N], all, n;
int main() {
read(n); ++n;
CC(f, 0x3f); all=bit(n)-1;
rep(i, n) rep(j, n) read(d[i][j]);
rep(k, n) rep(i, n) rep(j, n) d[i][j]=min(d[i][j], d[i][k]+d[k][j]);
f[0][0]=0;
for1(i, 0, all) for2(now, 0, n) for2(from, 0, n) if(i&bit(now))
f[i][now]=min(f[i][now], min(f[i-bit(now)][from]+d[from][now], f[i][from]+d[from][now]));
print(f[all][0]);
return 0;
}
テーマ説明Description
外で売っている人がいて、彼の手にはn部の注文があって、彼はn部のものを、それぞれn人の異なる取引先の手に送ります.n個の異なる顧客はそれぞれ1~n個の番号の都市にいる.出前は0番都市を出発して、それからn都市はすべて1回(1都市は何度も歩くことができます)、最後にまた0時(彼の職場)に戻って、最短の時間はいくらですかをお聞きします.現在、任意の2つの都市の直接通路の時間が知られている.
入力記述Input Description
1行目の正の整数n(1<=n<=15)
次は(n+1)*(n+1)のマトリクスで、マトリクスの数はいずれも10000を超えない正の整数です.行列のi行j列は、i−1番目の都市とj−1番目の都市との間の直接通路の時間を表す.もちろん、都市aから都市bへの直接通路時間と都市bから都市aへの直接通路時間は必ずしも同じではなく、つまり道路は一方向である.
出力記述Output Description
正の整数は、最も少ない時間を表します.
サンプル入力Sample Input
3
0 1 10 10
1 0 1 2
10 1 0 10
10 2 10 0
サンプル出力Sample Output
8
データ範囲とヒントData Size&Hint
1<=n<=15