bzoj1003(ZJOI2006)物流运输
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1003
一开始撕逼地以为是撕逼题。贪心什么的。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define ll long long using namespace std; const int T=105,N=25;const ll INF=0x7fffffff; int t,n,m,K,head[N],xnt,ky[T]; ll cd[(1<<20)+5],qd,lm,dis[N],mn,ans; bool vis[N]; struct Edge{ int next,to;ll w; Edge(int n=0,int t=0,ll w=0):next(n),to(t),w(w) {} }edge[805]; void add(int x,int y,ll z) { edge[++xnt]=Edge(head[x],y,z);head[x]=xnt; edge[++xnt]=Edge(head[y],x,z);head[y]=xnt; } bool ck(int s,int i){return s&(1<<i);} void dj(int s) { memset(dis,1,sizeof dis);dis[1]=0; priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q; memset(vis,0,sizeof vis);q.push(make_pair(0,1)); while(q.size()) { int k=q.top().second;q.pop(); while(vis[k]&&q.size())k=q.top().second,q.pop(); if(vis[k])break;vis[k]=1;if(k==n)break; for(int i=head[k],v;i;i=edge[i].next) if(!vis[v=edge[i].to]&&ck(s,v)&&dis[v]>dis[k]+edge[i].w) dis[v]=dis[k]+edge[i].w,q.push(make_pair(dis[v],v)); } cd[s]=dis[n]; } void init() { qd=((1<<1)|(1<<n));lm=(1<<(n+1));memset(cd,1,sizeof cd); for(int s=qd;s<lm;s++)dj(s); } int main() { scanf("%d%d%d%d",&t,&n,&K,&m);int x,y;ll z; while(m--) { scanf("%d%d%lld",&x,&y,&z); add(x,y,z); } init(); scanf("%d",&m);int p; while(m--) { scanf("%d%d%d",&p,&x,&y); for(int i=x;i<=y;i++)ky[i]|=(1<<p); } mn=INF; for(int i=1;i<=t;i++) { mn=INF; for(int s=qd;s<lm;s++) if((ky[i]&s)==0) mn=min(mn,(ky[i-1]&s)==0?cd[s]:cd[s]+K); ans+=mn; } printf("%lld",ans); return 0; }
结果并不是。主要是当前走这条路线不用切换的条件不是上一次能走这条路线,而是上一次走了这条路线。
然后去看了看TJ。啊,是区间dp呀。于是枚举区间长度,如何如何。但还是不对。
又去看TJ了。发现不应该是把两个区间dp值拼起来,而是前 j 个点的dp值+后面点的最短路值。或者至少记录一下当前dp值走了哪条路线,不然可能出现多加的切换费用。
其实最后发现可能不是因为这个错了。d j 的时候那个“ck(s,v)”,其实是“! ck(s,v)”。唉,不知道怎么过样例的。中间输出竟然也没看出来,真可怕。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define ll long long using namespace std; const int T=105,N=25;const ll INF=0x7fffffff; int t,n,m,K,head[N],xnt,ky[T]; ll dis[N],dp[T]; bool vis[N]; struct Edge{ int next,to;ll w; Edge(int n=0,int t=0,ll w=0):next(n),to(t),w(w) {} }edge[805]; void add(int x,int y,ll z) { edge[++xnt]=Edge(head[x],y,z);head[x]=xnt; edge[++xnt]=Edge(head[y],x,z);head[y]=xnt; } bool ck(int s,int i){return s&(1<<i);} ll dj(int s) { memset(dis,1,sizeof dis);dis[1]=0; priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q; memset(vis,0,sizeof vis);q.push(make_pair(0,1)); while(q.size()) { int k=q.top().second;q.pop(); while(vis[k]&&q.size())k=q.top().second,q.pop(); if(vis[k])break;vis[k]=1;if(k==n)break; for(int i=head[k],v;i;i=edge[i].next) if(!vis[v=edge[i].to]&&!ck(s,v)&&dis[v]>dis[k]+edge[i].w)// dis[v]=dis[k]+edge[i].w,q.push(make_pair(dis[v],v)); } return dis[n]; } ll sy(int l,int r) { int sm=0;for(int j=l;j<=r;j++)sm|=ky[j]; return dj(sm)*(r-l+1); } int main() { scanf("%d%d%d%d",&t,&n,&K,&m);int x,y;ll z; while(m--) { scanf("%d%d%lld",&x,&y,&z); add(x,y,z); } scanf("%d",&m);int p; while(m--) { scanf("%d%d%d",&p,&x,&y); for(int i=x;i<=y;i++)ky[i]|=(1<<p); } memset(dp,1,sizeof dp);dp[0]=0; for(int i=1;i<=t;i++) { for(int j=0;j<i;j++) dp[i]=min(dp[i],dp[j]+sy(j+1,i)+K); } printf("%lld",dp[t]-K); return 0; }