hdu6805 Deliver the Cake(拆点+最短路)

题意:

给定n个点m条边的带权无向图,表示有n个城市和m条路径
给定st和ed,表示起点和终点

现在你要从起点往终点送蛋糕
路途中你只能一只手拿蛋糕,如果把蛋糕从左手换到右手,需要x的代价

每个城市有奇怪的习俗,
如果这个城市被标为L,那么进入这个城市时,必须是左手拿蛋糕
如果这个城市被标为R,那么进入这个城市时,必须是右手拿蛋糕
如果这个城市被标为M,那么进入这个城市则没有限制。

问从起点到达终点的最小代价是多少

数据范围:n<=1e5,m<=2e5

解法:

显然我们只有在需要换手才能进入城市的时候才会主动换手,
如果点a到点b有边权为c的路径,且点a和点b的习俗不同,那么就将边权修改为c+x

如果a和b中有一个城市是M类似的呢?
一个优秀的解决方法是将M城市拆为两个点PL和PR
然后想上面一样建图即可

建完图跑起点到终点的最短路就是答案

注意:
这题spfa似乎被卡了,得用dj

ps:
pair是以第一关键字排序的,然而一开始我把编号存在前面了,路径长度存在后面,wa了好多发才发现。
太久没用dj,忘记了,晕倒。

code:

#include
using namespace std;
#define int long long
const int maxm=3e6+5;
int head[maxm],nt[maxm<<2],to[maxm<<2],w[maxm<<2],tot;
int mark[maxm];
int d[maxm];
char s[maxm];
int n,m,st,ed,val;
vector<int>id[maxm];
int idx;
void init(){
    tot=0;
    for(int i=1;i<=idx;i++){
        head[i]=0;
        id[i].clear();
    }
    idx=0;
}
void add(int x,int y,int z){
    tot++;nt[tot]=head[x];head[x]=tot;to[tot]=y;w[tot]=z;
    tot++;nt[tot]=head[y];head[y]=tot;to[tot]=x;w[tot]=z;
}
#define PI pair
int dj(){
    int rt=++idx;
    for(int v:id[st]){
        if(v==-1)continue;
        add(rt,v,0);
    }
    for(int i=1;i<=idx;i++){
        d[i]=1e18;
        mark[i]=0;
    }
    priority_queue<PI,vector<PI>,greater<PI> >q;
    d[rt]=0;
    q.push({0,rt});
    while(!q.empty()){
        int x=q.top().second;q.pop();//找出最小的
        if(mark[x])continue;
        mark[x]=1;//标记
        for(int i=head[x];i;i=nt[i]){
            int v=to[i];
            if(mark[v])continue;
            if(d[v]>d[x]+w[i]){
                d[v]=d[x]+w[i];
                q.push({d[v],v});
            }
        }
    }
    int ans=1e18;
    for(int v:id[ed]){
        if(v==-1)continue;
        ans=min(ans,d[v]);
    }
    return ans;
}
signed main(){
    ios::sync_with_stdio(0);
    int T;cin>>T;
    while(T--){
        init();
        cin>>n>>m>>st>>ed>>val;
        cin>>(s+1);
        for(int i=1;i<=n;i++){
            if(s[i]=='L'){
                id[i].push_back(++idx);
                id[i].push_back(-1);
            }else if(s[i]=='R'){
                id[i].push_back(-1);
                id[i].push_back(++idx);
            }else if(s[i]=='M'){
                id[i].push_back(++idx);
                id[i].push_back(++idx);
            }
        }
        for(int i=1;i<=m;i++){
            int x,y,z;cin>>x>>y>>z;
            for(int j=0;j<2;j++){
                if(id[x][j]==-1)continue;
                for(int k=0;k<2;k++){
                    if(id[y][k]==-1)continue;
                    add(id[x][j],id[y][k],z+val*(j!=k));
                }
            }
        }
        int ans=dj();
        cout<<ans<<endl;
    }
    return 0;
}

你可能感兴趣的:(hdu6805 Deliver the Cake(拆点+最短路))