[自己出的题] 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遍就不要喷人家啊略略略……

幸甚至哉,歌以咏志。

原文地址:https://www.cnblogs.com/DarthVictor/p/12822473.html