您的位置:首页 > 理论基础 > 计算机网络

hdu 4284 Travel (2012 天津网络赛 1007 )

2012-09-10 16:00 381 查看
这题当场没有做出来, 看了芳姐代码后面还弄出了个超时

,spfa 加位压缩的bfs过的;

先spfa算出目标点两两之间的最短距离;

bfs搜的是dp[i][j]; 当前所在点为i, 状态是j, 2进制j的第x位为1表示第x个目标点已经购买过了通行证;

复杂度O(15*(2^15))+O(15*15*spfa());险过

#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 113
#define maxm 11005
using namespace std;
int vv[maxm], nxt[maxm], ww[maxm], h[maxn], e;
int d[maxn], svis[maxn];

void link( int u, int v, int c )
{
vv[e] = v; ww[e] = c; nxt[e] = h[u]; h[u] = e++;
}

void spfa( int s )
{
memset( svis, 0, sizeof(svis) );
memset( d, -1, sizeof(d) );
d[s] = 0;
queue<int>q;
q.push( s );
while( !q.empty() ){
int u = q.front();
q.pop();
svis[u] = 0;
for( int j = h[u]; j+1; j = nxt[j] ){
int v = vv[j];
if( d[v] == -1 || d[v] > d[u] + ww[j] ){
d[v] = d[u] + ww[j];
if( !svis[v] )
svis[v] = 1, q.push( v );
}
}
}
}

int C[20], D[20], dd[20][20];
int dp[20][70000], vis[20][70000];
int num[20], H, S;
int bit[20], n, m, money;

int bfs(int is)
{
for( int i = 1; i <= H; i++ ){
memset( dp[i], -1, sizeof(int)*(bit[H+1]+5) );
memset( vis[i], 0, sizeof(int)*(bit[H+1]+5) );
}
//memset(dp, -1, sizeof(dp));
//memset(vis, 0, sizeof(vis));
queue<int> q;
if(is){
q.push(70000*S);
dp[S][0] = money;
vis[S][0] = 1;
}
else{
for( int i = 1; i <= H; i++ ){
if( dd[S][i] >= 0 && money >= dd[S][i] + D[i] ){
dp[i][bit[i]] = money - dd[S][i] - D[i] + C[i];
q.push( i * 70000 + bit[i] );
vis[i][bit[i]] = 1;
}
}
}
while( !q.empty() ){
int u = q.front(); q.pop();
int st = u / 70000, state = u % 70000;
vis[st][state] = 0;
if( dp[st][state] < 0 ) continue;
for( int i = 1; i <= H; i++ ){
if( dp[st][state] - dd[st][i] - D[i] < 0 )
continue;
if( (state&bit[i]) == 0 && dd[st][i] >= 0 ){
int stv = state | bit[i];
if( dp[i][stv] < dp[st][state] - dd[st][i] - D[i] + C[i] ){
dp[i][stv] = dp[st][state] - dd[st][i] - D[i] + C[i];
int v = i*70000 + stv;
if( !vis[i][stv] )
vis[i][stv] = 1, q.push( v );
}
}
}
}
for( int i = 1; i <= H; i++ )
if( dd[i][S] >= 0 && dp[i][bit[H+1]-1] - dd[i][S] >= 0 )
return 1;
return 0;
}
int main()
{
bit[1] = 1;
for( int i = 2; i <= 18; i++ ) bit[i] = bit[i-1]<<1;
int T;
int a, b, c;
scanf( "%d", &T );
while( T-- ){
scanf( "%d%d%d", &n, &m, &money );
e = 0;
memset( h, -1, sizeof(h) );
for( int i = 0; i < m; i++ ){
scanf( "%d%d%d", &a, &b, &c );
link( a, b, c );
link( b, a, c );
}
scanf( "%d", &H );
S = 0;
for( int i = 1; i <= H; i++ ){
scanf( "%d%d%d", &num[i], &C[i], &D[i] );
if( num[i] == 1 )
S = i;
}
int s = S;
if( !S ){
num[++H] = 1;
C[H] = 0; D[H] = 0;
S = H;
}
for( int i = 1; i <= H; i++ ){
spfa( num[i] );
for( int j = 1; j  <= H; j++ )
dd[i][j] = d[num[j]];
}
if( !s ) H--;  // 这一步非常重要, 它把最大复杂度O(2^16)降为O(2^15),这个跑了3s, 乘2就超时了;
if( bfs(s) )
printf( "YES\n" );
else
printf( "NO\n" );
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: