BZOJ4681 [jsoi2010]旅行

1.jpg

时间限制:

3S

空间限制:

256M
具体思路:DP
f[i][j][k]表示1-i,前L条路上用了 j条,L后的路上换了k条的最小代价
枚举一下L就有了一个复杂度O(nlognk^3)的做法
AC代码
#include<bits/stdc++.h>
using namespace std;
#define INF 100000000
#define P pair<int,int>
const int M=200010;
int n,i,j,m,k,top=1,L,mogic;
int first[M],next[M],to[M],last[M],len[M],f[100][200][50],ord[M];
bool vis[M*3];
struct E{int x,y,w;}e[M];
queue<P>q;
inline bool cmp(const E&a,const E&b){return a.w<b.w;}
int ans=2100000000,base=0;
void add(int x,int y,int z,int num)
{
    top++,to[top]=y;len[top]=z;ord[top]=num;
    if(first[x]==0)first[x]=top;else next[last[x]]=top;
    last[x]=top;
}
void PUSH(int x,int y,int z,int w)
{
    if(y>L||z>mogic)return;
    if(f[x][y][z]<=w)return;
    q.push(P(f[x][y][z]=w,(x<<13)|(y<<5)|(z)));
}
int main()
{
    scanf("%d%d%d",&n,&m,&mogic);
    for(i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
    sort(e+1,e+1+m,cmp);
    for(i=1;i<=m;i++)add(e[i].x,e[i].y,e[i].w,i),add(e[i].y,e[i].x,e[i].w,i);
    for(L=0;L<=m;L++)
    {
        base+=e[L].w;
        if(base>ans)break;
        for(i=1;i<=n;i++)for(j=0;j<=L;j++)for(k=0;k<=mogic;k++)f[i][j][k]=INF;
        memset(vis,0,sizeof(vis));
        PUSH(1,0,0,base);
        while(!q.empty())
        {
            P TOP=q.front();q.pop();
            int z=TOP.second&31;TOP.second>>=5;
            int y=TOP.second&255;TOP.second>>=8;
            int x=TOP.second;
            if(f[x][y][z]<TOP.first)continue;
            for(i=first[x];i;i=next[i])
            if(ord[i]<=L)
            {
                PUSH(to[i],y+1,z,TOP.first);
            }else PUSH(to[i],y,z,TOP.first+e[ord[i]].w),PUSH(to[i],y,z+1,TOP.first);
            
        }
        for(j=0;j<=L;j++)for(k=0;k<=mogic;k++)if(j+k<=L&&f[n][j][k]<ans)ans=f[n][j][k];
    }
    printf("%d",ans);
    return 0;
}

 

原文地址:https://www.cnblogs.com/Orange-User/p/8507160.html