[ZJOI2006]物流运输(状压写法)
[ZJOI2006]物流运输
https://ac.nowcoder.com/acm/problem/20469
m这么小,不用状压也太扯淡了
我们发现有价值的是每条路线上的经过的点集合
定义为第
天点,目前走集合为
的路线的最小花费
那么使用爆搜出所有路线(当然要剪枝),记录对应状态和花费
发现数组的第一维可以滚动数组变成
又因为每条路线都有点,所以可以去掉变成
就是枚举当前第
天的路线,再枚举上一天的路线,这样是
的
其实上一天我们只需要最小值就好了,所以过程中就可以取最小值
跑起来也很快
#include <bits/stdc++.h>
using namespace std;
const int maxn=209;
int f[1<<19],vis[209],isok[209],ju[1<<18],dp[2][1<<18];
int n,m,k,e;
struct p{
int to,nxt,w;
}d[maxn*maxn]; int head[maxn*maxn],cnt=1;
void add(int u,int v,int w){ d[cnt]=(p){v,head[u],w},head[u]=cnt++; }
void dfs(int u,int state,int dis)
{
if( dis>=f[state] ) return;
f[state]=dis;
if( u==m )
{
state^=(1<<(m-2));
ju[state] = min( ju[state],dis ); return;
}
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to; if( vis[v] ) continue;
vis[v]=1;
dfs(v,state|(1<<(v-2)),dis+d[i].w );
vis[v]=0;
}
}
int main()
{
cin >> n >> m >> k >> e;
memset(ju,0x3f,sizeof(ju));
memset(f,0x3f,sizeof(f));
for(int i=1;i<=e;i++)
{
int l,r,w; cin >> l >> r >> w;
add(l,r,w); add(r,l,w);
}
cin >> e;
for(int i=1;i<=e;i++)
{
int id,l,r; cin >> id >> l >> r;
for(int j=l;j<=r;j++) isok[j]|=(1<<(id-2));
}
vis[1]=1;
dfs(1,0,0);
int last=0;
for(int i=1;i<=n;i++)
{
int temp=1e9,t=(i&1);
for(int j=0;j<(1<<(m-2));j++)
{
if( ju[j]==1e9 ) { dp[t][j]=1e9; continue; }
if( isok[i]&j ) { dp[t][j]=1e9; continue; }
dp[t][j]=min( dp[t^1][j]+ju[j],last+k+ju[j] );
temp = min( temp,dp[t][j] );
}
last=temp;
}
cout << last;
}
巨人网络公司福利 91人发布