• [自己出的题] 02的爱恋题解


    题目

    原题链接
    出题人:博主(DarthVictor) 造数据:(zhl) 协助:(gyz)
    现属于洛谷本团队题库。

    解说

    五一假期组织了一起三个小组互相出题互相做的活动,每组两道。(gyz)大佬自己扛下一道(链接),我想出一道图论,就开始往那个方面想,最后先想出来的版本是没有秒杀武器的,想的标准思路是把有权值的点拆点来解决,但题目提出之后很快(gyz)大佬就提出了不拆点的思路。所以还是太简单了,得想办法再加难度……后来想到了原来做过的一道冻结,就想到要不加上一个秒杀武器,这样既引入了分层图还能强迫做的人拆点……
    然后就有了这个东西。由于本人蒟蒻,知识面浅薄,本题的数据由(zhl)大佬制作。
    下面就说一下我的标程的思路:
    普通的点就直接建双层图,传送门不过是在两个点之间建一条权值为(0)的路而已。遇到有权值的点,就拆为两个点,一个点连所有入边,另一个连所有出边,之后连入点再连一条权值为(0)的路到第二层的出点,这样经过有权值的点就必须过拆开的点之间的路,如果使用武器就可以不花费地抵达第二层,之后就没法再次使用。这样以后再跑一遍最短路,取第一层终点和第二层终点距离的最小值即可(注意取最小值)。
    之后又是(gyz)想出来其他做法:不拆点,把通往第二层的梯子的权值设为点权的相反数,这样上第二层就能抵消点权,之后用(SPFA)跑最短路即可。
    本来我们想卡掉非标程的做法,就想造一个卡(SPFA)的图,结果发现即便是这样的图(SPFA)也并不慢,毕竟不用拆点,边比较少。所以我觉得既然这也是一种思路,那就不卡了。
    写的时候代码的细节还是挺多的。因为各种细节,我的标程卡了两天才改完所有错误……

    代码

    标程代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1200000+5,maxe=10000000+5,INF=0x3f3f3f3f;
    int n,m,x,y,tot,dy[maxn],dis[maxn],head[maxn];
    bool vis[maxn];
    struct edge{
    	int to,next,w;
    }e[maxn];
    inline int read(){
       int s=0,w=1;
       char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
       while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
       return s*w;
    } 
    struct cun{
    	int a,b,l;
    }temp[maxe];
    void add(int a,int b,int l){
    	e[tot].w=l;
    	e[tot].to=b;
    	e[tot].next=head[a];
    	head[a]=tot;
    	tot++;
    }
    struct Node{
        int id,val;
        Node(){}
        Node(int a,int b){
            id=a;val=b;
        }
        bool operator < (const Node&A)const{
            return val>A.val;
        }    
    };
    void Dijs(){
        memset(dis,0x3f,sizeof(dis));
        priority_queue<Node> q;
        dis[1]=0;
        q.push(Node(1,0));
        while(!q.empty()){
            Node u=q.top();q.pop();
            if(vis[u.id])continue;
            vis[u.id]=1;
            for(int i=head[u.id];i;i=e[i].next){
                int v=e[i].to,w=e[i].w;
                if(dis[v]>dis[u.id]+w){
                    dis[v]=dis[u.id]+w;
                    q.push(Node(v,dis[v]));
                }
            }
        }
    }
    int main(){
    	tot=1;
    	n=read(); m=read(); x=read(); y=read();
    	for(int i=1;i<=m;i++){
    		temp[i].a=read();
    		temp[i].b=read();
    		temp[i].l=read();
    	}
    	for(int i=1;i<=x;i++){
    		int u,w;
    		u=read(); w=read();
    		dy[u]=n+i;
    		add(u,dy[u],w);
    		add(u+n+x+1,dy[u]+n+x+1,w);
    		add(u,dy[u]+n+x+1,0);
    	}
    	for(int i=1;i<=m;i++){
    		if(dy[temp[i].a]){
    			add(dy[temp[i].a],temp[i].b,temp[i].l);
    			add(dy[temp[i].a]+n+x+1,temp[i].b+n+x+1,temp[i].l);
    		}
    		else{
    			add(temp[i].a,temp[i].b,temp[i].l);
    			add(temp[i].a+n+x+1,temp[i].b+n+x+1,temp[i].l);
    		}
    	}
    	for(int i=1;i<=y;i++){
    		int a,b;
    		a=read(); b=read();
    		if(dy[a]){
    			add(dy[a],b,0);
    			add(dy[a]+n+x+1,b+n+x+1,0);
    		}
    		else{
    			add(a,b,0);
    			add(a+n+x+1,b+n+x+1,0);
    		}
    	}
    	Dijs();
    	if(dis[n+n+x+1]==INF&&dis[n]==INF) printf("-1");
    	else printf("%d",min(dis[n+n+x+1],dis[n]));
    	return 0;
    }
    

    标程·改

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1200000+5,maxe=10000000+5,INF=0x3f3f3f3f;
    int n,m,x,y,tot,dy[maxn],dis[maxn],head[maxn];
    bool vis[maxn];
    struct edge{
    	int to,next,w;
    }e[maxn];
    struct cun{
    	int a,b,l;
    }temp[maxe];
    void add(int a,int b,int l){
    	e[tot].w=l;
    	e[tot].to=b;
    	e[tot].next=head[a];
    	head[a]=tot;
    	tot++;
    }
    int read(){
       int s=0,w=1;
       char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
       while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
       return s*w;
    } 
    void Spfa(int begin){
    	deque<int> q; 
    	memset(dis,0x3f,sizeof(dis));
    	dis[begin]=0,vis[begin]=1;
    	q.push_back(begin);
    	while(!q.empty()){
    		int u=q.front();
    		q.pop_front();
    		vis[u]=0;
    		for(int i=head[u];i;i=e[i].next){
    			int v=e[i].to;
    			if(dis[v]>dis[u]+e[i].w){
    				dis[v]=dis[u]+e[i].w;
    				if(!vis[v]){
    					if(!q.empty()&&dis[v]>=dis[q.front()]) q.push_back(v);
                        else q.push_front(v);
    					vis[v]=1;
    				}
    			}
    		}
    	}
    }
    int main(){
    	tot=1;
    	n=read(); m=read(); x=read(); y=read();
    	for(int i=1;i<=m;i++){
    		temp[i].a=read();
    		temp[i].b=read();
    		temp[i].l=read();
    	}
    	for(int i=1;i<=x;i++){
    		int u,w;
    		u=read(); w=read();
    		dy[u]=n+i;
    		add(u,dy[u],w);
    		add(u+n+x+1,dy[u]+n+x+1,w);
    		add(u,dy[u]+n+x+1,0);
    	}
    	for(int i=1;i<=m;i++){
    		if(dy[temp[i].a]){
    			add(dy[temp[i].a],temp[i].b,temp[i].l);
    			add(dy[temp[i].a]+n+x+1,temp[i].b+n+x+1,temp[i].l);
    		}
    		else{
    			add(temp[i].a,temp[i].b,temp[i].l);
    			add(temp[i].a+n+x+1,temp[i].b+n+x+1,temp[i].l);
    		}
    	}
    	for(int i=1;i<=y;i++){
    		int a,b;
    		a=read(); b=read();
    		if(dy[a]){
    			add(dy[a],b,0);
    			add(dy[a]+n+x+1,b+n+x+1,0);
    		}
    		else{
    			add(a,b,0);
    			add(a+n+x+1,b+n+x+1,0);
    		}
    	}
    	Spfa(1);
    	if(dis[n+n+x+1]==INF&&dis[n]==INF) printf("-1");
    	else printf("%d",min(dis[n+n+x+1],dis[n]));
    	return 0;
    }
    

    gjk大佬AC代码

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    using namespace std;
    
    inline long long read(){
    	long long x = 0, w = 1;
    	char ch = getchar();
    	for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
    	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10ll + ch - '0';
    	return x * w;
    }
    
    const int maxn = 1000010;
    int tot, head[maxn*2];
    
    struct node{
        int to, nxt;
    	long long w;
    }edge[maxn << 2];
    
    inline void add(int x, int y, long long z){
         edge[++tot].to = y;
         edge[tot].nxt = head[x];
         edge[tot].w = z;
         head[x] = tot;
    }
    
    long long dis[maxn*2];
    bool vis[maxn*2];
    int val[maxn*2];
    
    inline void spfa(int x){
        memset(dis,0x3f,sizeof(dis));
        queue<int> q;
        q.push(x);
        dis[x] = 0;
        vis[x] = 1;
        while(!q.empty()){
            int now=q.front();
            q.pop();
            vis[now] = 0;
            for(int i = head[now]; i; i = edge[i].nxt){
                int v = edge[i].to;
                if(dis[v] > dis[now] + edge[i].w){
                    dis[v] = dis[now] + edge[i].w;
                    if(!vis[v]){
                        vis[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
    }
    
    int main(){
        int n = read(), m = read(), x = read(), y = read();
        for(int i = 1; i <= m; i++){
            int u = read(), v = read(), w = read();
            add(u, v, w);
            add(u+n, v+n, w);
        }
        for(int i = 1; i <= x; i++){
            int u = read();
            val[u] = read();
            val[u+n]=val[u];
        }
        for(int i = 1; i <= y; i++){
            int u = read(), v = read();
            add(u, v, 0);
            add(u+n, v+n, 0);
        }
        for(int i=1;i<=2*n;i++)
        	for(int j=head[i];j;j=edge[j].nxt){
        		add(i,edge[j].to+n,edge[j].w);
        		edge[j].w+=val[edge[j].to];
        	}
        spfa(1);
        if(dis[n]>=1e17)
        	printf("-1");
        else
        	cout << min(dis[n],dis[2*n]) << endl;
        return 0;
    }
    

    lc大佬AC代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int maxd=300005,maxb=3301005;
    int head[maxd],tot=1;
    struct asd{
        int to,next,val;
    }b[maxb];
    int jla[maxb],jlb[maxb],jlc[maxb];
    inline void ad(int aa,int bb,int cc){
        b[tot].to=bb;
        b[tot].next=head[aa];
        b[tot].val=cc;
        head[aa]=tot++;
    }
    int diss[maxd];
    int n,m,x,y;
    struct jie{
        int num,dis,kk;
        jie(int aa=0,int bb=0,int cc=0){
            num=aa,dis=bb,kk=cc;
        }
        bool operator < (const jie &A) const{
            return dis>A.dis;
        }
    };
    priority_queue<jie> q;
    int dis[maxd][2];
    bool vis[maxd][2];
    void solve(){
        memset(dis,0x3f,sizeof(dis));
        q.push(jie(1,0,0));
        dis[1][0]=0;
        while(!q.empty()){
            jie xx=q.top();
            q.pop();
            if(vis[xx.num][xx.kk]==true) continue;
            vis[xx.num][xx.kk]=true;
            for(int i=head[xx.num];i!=-1;i=b[i].next){
                int u=b[i].to;
                if(dis[u][xx.kk]>dis[xx.num][xx.kk]+b[i].val){
                    dis[u][xx.kk]=dis[xx.num][xx.kk]+b[i].val;
                    q.push(jie(u,dis[u][xx.kk],xx.kk));
                }
                if(xx.kk<1 && dis[u][xx.kk+1]>dis[xx.num][xx.kk]+b[i].val-diss[u]){
                    dis[u][xx.kk+1]=dis[xx.num][xx.kk]+b[i].val-diss[u];
                    q.push(jie(u,dis[u][xx.kk+1],xx.kk+1));
                }
            }
        }
    }
    int main(){
        memset(head,-1,sizeof(head));
        scanf("%d%d%d%d",&n,&m,&x,&y);
        for(int i=1;i<=m;i++){
            int aa,bb,cc;
            scanf("%d%d%d",&aa,&bb,&cc);
            jla[i]=aa,jlb[i]=bb,jlc[i]=cc;
        }
        for(int i=1;i<=x;i++){
            int aa,bb;
            scanf("%d%d",&aa,&bb);
            diss[aa]=bb;
        }
        for(int i=1;i<=y;i++){
            int aa,bb;
            scanf("%d%d",&aa,&bb);
            jla[m+i]=aa,jlb[m+i]=bb,jlc[m+i]=0;
        }
        for(int i=1;i<=m+y;i++){
            ad(jla[i],jlb[i],jlc[i]+diss[jlb[i]]);
        }
        int ans=0x3f3f3f3f;
        solve();
        ans=min(dis[n][0],dis[n][1]);
        if(ans==0x3f3f3f3f) printf("-1
    ");
        else printf("%d
    ",ans);
        return 0;
    }
    

    尾声

    几种版本的代码都附在上面了供大家研究。
    对比一下:


    这次出题真的是感觉出题比做题难……要考虑的太多了,可能会有什么水题做法,怎么能卡掉,设置多长的时间合适……真的恶心到了……
    还有@gjk说我们题简单您倒是一遍A掉啊WA了5遍就不要喷人家啊略略略……

    幸甚至哉,歌以咏志。

  • 相关阅读:
    LWIP的底层结构(物理层)
    Source insight 支持汇编
    Camera Vision
    i2c-tools的使用方法及举例
    浅析C语言中strtol()函数与strtoul()函数的用法
    CF540C Ice Cave
    CF540B School Marks
    hdu5122 K.Bro Sorting
    hdu1013 Digital Roots
    蓝桥杯 算法提高 递推求值
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/12822473.html
Copyright © 2020-2023  润新知