刷题记录 kuangbin带你飞专题四:最短路练习

写之前先给这个专题做个总结
知识点:单源最短路,全源最短路,求最短路中的最长边,bellman ford算法求有负权的最短路,bellman or SPFA判断环,反向建图,差分约束,层次图建立层点(连通点)。

应该是覆盖最短路所有内容了

1.POJ 2387 Til the Cows Come Home

模板题

2.POJ 2253 Frogger

Floyd模板题,只要看到这个数据范围冲就完事了(n<=800)

3.POJ 1797 Heavy Transportation

题意:求能到达终点的最大边权最小
看题意很明显这个题可以用二分答案做,然而我一直莫名其妙的wa?用最大生成树的最小边也wa,然后换了变形dij才过…
dij的堆要写成大根堆,因为要优先选择边权大,不然会wa

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 200010
#define maxm 200010
using namespace std;
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
struct edge{
	int v,w;
}e[maxm];
int cnt,n,m,s,vis[maxn],dis[maxn];
vector<edge>p[100005];
struct node{
	int w,now;
	bool operator <(const node&x)const
	{
		return w<x.w;
	}
};
priority_queue<node>q;
inline void dij(int s){
	memset(dis,0,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[s]=0x3f3f3f3f;
	q.push((node){0,s});
	while(!q.empty()){
		node x=q.top();
		q.pop();
		int u=x.now;
		if(vis[u])continue;
		vis[u]=1;
		for(int i=0;i<p[u].size();i++){
			int v=p[u][i].v;
			if(dis[v]<min(dis[u],p[u][i].w)){
				dis[v]=min(dis[u],p[u][i].w);
				q.push((node){dis[v],v});
			}
		}
	}
}
signed main(){
	int tt,qq=0;
	cin>>tt;
	while(tt--){
		qq++;
    	n=read(),m=read();
    	memset(p,0,sizeof(p));
    	for(int i=1,x,y,z;i<=m;i++){
    		x=read(),y=read(),z=read();
    		p[x].push_back((edge){y,z});
    		p[y].push_back((edge){x,z});
    	}
    	dij(1);
    	printf("Scenario #%d:\n",qq);
    	printf("%d\n\n",dis[n]);
    }
	return 0;
}

4.POJ 3268 Silver Cow Party

题意:求所有牛来回party最短路的最大值
见到这种来回的,一般都是直接建反图就完事了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 200010
#define maxm 200010
const int inf=0x3f3f3f3f;
using namespace std;
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
struct edge{
	int v,w;
}e[maxm];
int cnt,n,m,mm,s,vis[maxn],dis[maxn],dis1[maxn],vis1[maxn];
vector<edge>p[100005],p1[100005];
struct node{
	int w,now;
	bool operator <(const node&x)const
	{
		return w>x.w;
	}
};
inline void dij(int s){
	priority_queue<node>q;
	for(int i=1;i<=n;i++){
		dis[i]=inf;
	}
	memset(vis,0,sizeof(vis));
	dis[s]=0;
	q.push((node){0,s});
	while(!q.empty()){
		node x=q.top();
		q.pop();
		int u=x.now;
		if(vis[u])continue;
		vis[u]=1;
		for(int i=0;i<p[u].size();i++){
			int v=p[u][i].v;
			if(dis[v]>dis[u]+p[u][i].w){
				dis[v]=dis[u]+p[u][i].w;
				q.push((node){dis[v],v});
			}
		}
	}
}
inline void dij1(int s){
	priority_queue<node>q;
	for(int i=1;i<=n;i++){
		dis1[i]=inf;
	}
	memset(vis1,0,sizeof(vis1));
	dis1[s]=0;
	q.push((node){0,s});
	while(!q.empty()){
		node x=q.top();
		q.pop();
		int u=x.now;
		if(vis1[u])continue;
		vis1[u]=1;
		for(int i=0;i<p1[u].size();i++){
			int v=p1[u][i].v;
			if(dis1[v]>dis1[u]+p1[u][i].w){
				dis1[v]=dis1[u]+p1[u][i].w;
				q.push((node){dis1[v],v});
			}
		}
	}
}
signed main(){
	n=read(),m=read(),s=read();
	mm=0;
	for(int i=1,x,y,z;i<=m;i++){
		x=read(),y=read(),z=read();
		p[x].push_back((edge){y,z});
		p1[y].push_back((edge){x,z});
	}
	for(int i=1;i<=n;i++){
		if(i==s)continue;
		dij(i);
    	dij1(i);
		mm=max(mm,dis[s]+dis1[s]);
	//	cout<<i<<" "<<dis[s]<<" "<<dis1[s]<<endl;
	}
	cout<<mm;
	return 0;
}

5.POJ 1860 Currency Exchange

读题难度>解题难度
判环模板题

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 200010
#define maxm 200010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,cnt,ans,c=1;
double r1,r2,c1,c2;
int k;
double money;
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
struct edge{
	int u,v;
	double r,c;
};
vector<edge>e;
double d[1005];
bool bellman(){
	memset(d,0,sizeof(d));
	d[k]=money;
	for(int i=1;i<n;i++){
		int ok=0;
		for(int j=0;j<e.size();j++){
			if((d[e[j].u]-e[j].c)*e[j].r>d[e[j].v]){
				d[e[j].v]=(d[e[j].u]-e[j].c)*e[j].r;
				ok=1;
			}
		}
		if(!ok)break;
	}
	for(int i=0;i<e.size();i++){
		if((d[e[i].u]-e[i].c)*e[i].r>d[e[i].v]){
			return true;
		}
    }
    return false;
}
signed main(){
	cin>>n>>m>>k>>money;
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y>>r1>>c1>>r2>>c2;
		e.push_back((edge){x,y,r1,c1});
		e.push_back((edge){y,x,r2,c2});
	}
	if(bellman())cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
	return 0;
}

6.POJ 3259 Wormholes

判环,比上一题还简单,故略

7.POJ 1502 MPI Maelstrom

读入难度>>解题难度
读x的时候一定要注意这个坑…用string的话会出问题
读入完直接跑Floyd就没了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 200010
#define maxm 200010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,w,cnt,ans,c=1;
int dis[105][105];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)dis[i][j]=0;
			else dis[i][j]=inf;
		}
	}
	for(int i=2;i<=n;i++){
		for(int j=1;j<=i-1;j++){
			char x[50];
			scanf("%s",x);
			if(x[0]=='x'){
				continue;
			}
			else{
				int k=atoi(x);
				dis[i][j]=k;
				dis[j][i]=k;
			}
		}
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
			}
		}
	}
	int mm=0;
	for(int i=2;i<=n;i++){
		if(dis[1][i]!=inf){
			mm=max(mm,dis[1][i]);
		}
	}
	cout<<mm<<endl;
	return 0;
}

8.POJ 3660 Cow Contest

给出一些列大小关系,问有多少头牛的排名可以确定
思路其实很简单,以大小关系建立单向边,跑一遍Floyd,求出来dis[i][j]的值不为inf就cnt[i] ,cnt[j]都+1,统计完之后如果值为n-1就代表跟所有其他的牛都有确定大小关系,即为答案

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,t,ans,mxn;
int dis[505][505],vis[505][505],cnt[505];
int main(){
	cin>>n>>m;
	memset(dis,inf,sizeof(dis));
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		dis[x][y]=1;
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			if(dis[i][j]!=inf)cnt[j]++,cnt[i]++;
		}
	}
	for(int i=1;i<=n;i++){
		if(cnt[i]==n-1)ans++;
	}
	cout<<ans;
	return 0;
}

9.POJ 2240 Arbitrage

套利,判环,这题之前在洛谷上面做过,用map乱搞,跑Floyd判断是否有dis最终大于1,有就是有环,然而交vj直接给我TLE,换成bellman 判环 TLE,(poj懂的都懂好吧)没有氧气优化又没有C++11真的吐了,傻逼测评姬

最终 SPFA判环可过

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
int n,f;
double dis[50][50];
string a;
map<string,int>m;
double s;
string x,y;
struct edge{
	int v;
	double w;
};
vector<edge>e[5005];
double d[1005];
int cnt[10050];
int vis[10050];
bool spfa(){
	int ct=0;
	memset(cnt,0,sizeof(cnt));
	queue<int>q;
	for(int i=1;i<=n;i++){
		d[i]=1;
		vis[i]=1,
		q.push(i);
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=0;i<e[u].size();i++){
			int v=e[u][i].v;
			double w=d[u]*e[u][i].w;
			if(d[v]<w){
				d[v]=w;
				cnt[v]=cnt[u]+1;
				if(ct>4*n)return true;
				if(cnt[v]>=n)return true;
				if(vis[v]==0)q.push(v),vis[v]=1;
			}
		}
	}
	return false;
}
int main(){
	while(1){
		int t;
		f++;
		cin>>t;
		if(t==0)break;
		m.clear();
		memset(e,0,sizeof(e));
		for(int i=1;i<=t;i++){
			cin>>a;
			m[a]=i;
		}
		cin>>n;
		for(int i=1;i<=n;i++){
			double z;
			cin>>x>>z>>y;
			e[m[x]].push_back((edge){m[y],z});
		}
		
		if(spfa())printf("Case %d: Yes\n",f);
		else printf("Case %d: No\n",f);
	}
	return 0;
}

10.POJ 1511 Invitation Cards

UVA721
在vj上面一直wa,为了验证我的程序是对的,特意注册账号去UVA交了原题,AC了,poj爬
思路:建反图
(本代码在vj上过不了)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 1000010
#define maxm 1000010
const int inf=0x3f3f3f3f;
using namespace std;
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
struct edge{
	int v,w;
}e[maxm];
int cnt,n,m,mm,s,vis[maxn],dis[maxn],dis1[maxn],vis1[maxn];
vector<edge>p[1000005],p1[1000005];
struct node{
	int w,now;
	bool operator <(const node&x)const
	{
		return w>x.w;
	}
};
inline void dij(int s){
	priority_queue<node>q;
	for(int i=1;i<=n;i++){
		dis[i]=inf;
	}
	memset(vis,0,sizeof(vis));
	dis[s]=0;
	q.push((node){0,s});
	while(!q.empty()){
		node x=q.top();
		q.pop();
		int u=x.now;
		if(vis[u])continue;
		vis[u]=1;
		for(int i=0;i<p[u].size();i++){
			int v=p[u][i].v;
			if(dis[v]>dis[u]+p[u][i].w){
				dis[v]=dis[u]+p[u][i].w;
				q.push((node){dis[v],v});
			}
		}
	}
}
inline void dij1(int s){
	priority_queue<node>q;
	for(int i=1;i<=n;i++){
		dis1[i]=inf;
	}
	memset(vis1,0,sizeof(vis1));
	dis1[s]=0;
	q.push((node){0,s});
	while(!q.empty()){
		node x=q.top();
		q.pop();
		int u=x.now;
		if(vis1[u])continue;
		vis1[u]=1;
		for(int i=0;i<p1[u].size();i++){
			int v=p1[u][i].v;
			if(dis1[v]>dis1[u]+p1[u][i].w){
				dis1[v]=dis1[u]+p1[u][i].w;
				q.push((node){dis1[v],v});
			}
		}
	}
}
signed main(){
	int tt;
	cin>>tt;
	while(tt--){
    	n=read(),m=read();
    	mm=0;
    	memset(p,0,sizeof(p));
	    memset(p1,0,sizeof(p1));
    	for(int i=1,x,y,z;i<=m;i++){
    		x=read(),y=read(),z=read();
	    	p[x].push_back((edge){y,z});
	    	p1[y].push_back((edge){x,z});
    	}
    	dij(1);
    	dij1(1);
	   	for(int i=2;i<=n;i++){
	    	mm+=dis[i]+dis1[i];
	    }
	    cout<<mm<<endl;
	}
	return 0;
}

11.POJ 3159 Candies

差分约束,太水了,甚至不能算模板,直接用dij建单边就过了
模板在后面

12.POJ 2502 Subway

此题难点在于建图,建图难度>>解题难度
对每个相间车站建直线距离边,再对所有点建欧几里得距离边,最后跑一遍dij

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
struct edge{
	int v;
	double w;
}e[maxm];
int num;
int cnt,n,m,s,vis[maxn];
double dis[maxn];
vector<edge>p[100005];
struct node{
	double w;
	int now;
	bool operator <(const node&x)const
	{
		return w>x.w;
	}
};
priority_queue<node>q;
inline void dij(int s){
	for(int i=1;i<=num;i++){
		dis[i]=inf;
	}
	memset(vis,0,sizeof(vis));
	dis[s]=0;
	q.push((node){0,s});
	while(!q.empty()){
		node x=q.top();
		q.pop();
		int u=x.now;
		if(vis[u])continue;
		vis[u]=1;
		for(int i=0;i<p[u].size();i++){
			int v=p[u][i].v;
			if(dis[v]>dis[u]+p[u][i].w){
				dis[v]=dis[u]+p[u][i].w;
				q.push((node){dis[v],v});
			}
		}
	}
}
double juli(double x1,double y1,double x2,double y2,double tt){
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))/tt/1000*60;
}
struct ta{
	double x,y;
}stop[505];
int sx,sy,dx,dy;
int main(){
	sx=read(),sy=read(),dx=read(),dy=read();
	stop[1].x=sx;
	stop[1].y=sy;
	memset(dis,0x3f3f3f3f,sizeof(dis));
	int x,y;
	num=2;
	while(~scanf("%d%d",&x,&y)){
		stop[num].x=x,stop[num].y=y;
		int xx,yy;
		while(~scanf("%d%d",&xx,&yy)){
			if(xx==-1&&yy==-1)break;
			stop[num+1].x=xx;
			stop[num+1].y=yy;
			double d=juli(x,y,xx,yy,40);
			p[num].push_back((edge){num+1,d});
			p[num+1].push_back((edge){num,d});
			x=xx;
			y=yy;
			num++;
		}
		num++;
	}
	stop[num].x=dx;
	stop[num].y=dy;
	for(int i=0;i<=num;i++){
		for(int j=0;j<=num;j++){
			if(i==j)continue;
			double d=juli(stop[i].x,stop[i].y,stop[j].x,stop[j].y,10);
			p[i].push_back((edge){j,d});
		}
	}
	dij(1);
	printf("%.f",dis[num]);
	return 0;
}

13.POJ 1062 昂贵的聘礼

此题的题意真的是坑的让人吐血…最开始理解成探险家最开始等级无限,接触一个人之后就降等,降等之后不能跟高级商家交易,结果真正的题意是:探险家接触过的所有人的等级差距都不能超过m
比如酋长的等级是5,m是2,你最开始跟等级7的人交易过,你就不能再跟<5的人交易了,所有其实是询问长度为m的一个区间(并且酋长的等级一定要包含在区间内),一共跑m+1次dij,建图很简单,每个物品从0向它建一条原价边,再从它的前置物建优惠边即可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
#define int long long
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
struct edge{
	int v,w,dengji;
}e[maxm];
int cnt,n,m,s,vis[maxn],dis[maxn];
vector<edge>p[100005];
struct node{
	int w,now;
	bool operator <(const node&x)const
	{
		return w>x.w;
	}
};
priority_queue<node>q;
inline void dij(int s,int dj1,int dj2){
	for(int i=1;i<=n;i++){
		dis[i]=inf;
	}
	memset(vis,0,sizeof(vis));
	dis[0]=0;
	q.push((node){0,s});
	while(!q.empty()){
		node x=q.top();
		q.pop();
		int u=x.now;
		if(vis[u])continue;
		vis[u]=1;
		for(int i=0;i<p[u].size();i++){
			int v=p[u][i].v;
			if(dis[v]>dis[u]+p[u][i].w&&p[u][i].dengji>=dj1&&p[u][i].dengji<=dj2){
				dis[v]=dis[u]+p[u][i].w;
				q.push((node){dis[v],v});
			}
		}
	}
}
signed main(){
	m=read(),n=read();
	int zui;
	for(int i=1;i<=n;i++){
		int money,dj,q;
		money=read(),dj=read(),q=read();
		if(i==1)zui=dj;
		p[0].push_back((edge){i,money,dj});
		for(int j=1;j<=q;j++){
			int x,y;
			x=read(),y=read();
			p[x].push_back((edge){i,y,dj});
		}
	}
	int qq=m;
	int mm=0x3f3f3f3f;
	for(int i=1;i<=m+1;i++){
		dij(0,zui-qq,zui-qq+m);
//		cout<<zui-qq<<" "<<zui-qq+m<<endl;;
		qq--;
		mm=min(dis[1],mm);
	}
	cout<<mm;
	return 0;
}

14.POJ 1847 Tram

每个车站第一条边权为0,其他为1,然后就是Floyd傻逼题了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
int dis[105][105];
int a,b,n;
int m;
signed main(){
	cin>>n>>a>>b;
	memset(dis,inf,sizeof(dis));
	for(int i=1;i<=n;i++){
		int t;
		cin>>t;
		for(int j=1;j<=t;j++){
			int x;
			x=read();
			if(j==1)dis[i][x]=0;
			else dis[i][x]=1;
		}
	}
//	for(int i=1;i<=n;i++){
//		for(int j=1;j<=n;j++){
///			cout<<dis[i][j]<<" ";
//		}
//		cout<<endl;
//	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
			}
		}
	}
	if(dis[a][b]!=inf)cout<<dis[a][b];
	else cout<<"-1";
	return 0;
}

15.LightOJ 1074 Extended Traffic

三次方会出负数…spfa判环
询问的点不在环上且可到达输出距离,否则直接疑惑

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
int d[5005];
int n,a[5005],q[5005];
int m,vis[5005],cs[5005];
struct edge{
	int v,w;
};
vector<edge>e[5005];
void spfa(){
	memset(d,inf,sizeof(d));
	memset(vis,0,sizeof(vis));
	memset(cs,0,sizeof(cs));
	queue<int>q;
	d[1]=0;
	cs[1]=1;
	q.push(1);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=0;i<e[u].size();i++){
			int v=e[u][i].v;
			int w=e[u][i].w;
			if(d[v]>d[u]+w){
				d[v]=d[u]+w;
				if(vis[v]==0&&cs[v]<=n){
					cs[v]++;
					q.push(v);
					vis[v]=1;
				}
			}
		}
	}
}
signed main(){
	int tt,qq=0,p;
	cin>>tt;
	while(tt--){
		cin>>n;
		qq++;
		for(int i=1;i<=n;i++){
			a[i]=read();
		}
		cin>>m;
		for(int i=1;i<=m;i++){
			int u,v;
			u=read(),v=read();
			int dis=(a[v]-a[u])*(a[v]-a[u])*(a[v]-a[u]);
			e[u].push_back((edge){v,dis});
		}
		cin>>p;
		for(int i=1;i<=p;i++){
			q[i]=read();
		}
		spfa();
		printf("Case %d:\n",qq);
		for(int i=1;i<=p;i++){
			if(d[q[i]]<3||d[q[i]]>=inf||cs[q[i]]>n){
				printf("?\n");
			}
			else{
				printf("%d\n",d[q[i]]);
			}
		}
		memset(e,0,sizeof(e));
	}
	return 0;
}

16.HDU 4725 The Shortest Path in Nya Graph

建图题
每个点有它所属的层,层之间有通道,对层之间所有点全部建边肯定会炸,所以建立每一层的层点,即专门用来连接属于这一层其他点的点

#include<bits/stdc++.h>
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
struct edge{
	int v,w;
}e[maxm];
int cnt,n,m,c,vis[maxn],dis[maxn];
vector<edge>p[200005];
int cs[200005],layer[200005];
struct node{
	int w,now;
	bool operator <(const node&x)const
	{
		return w>x.w;
	}
};
priority_queue<node>q;
inline void dij(int s){
	memset(dis,inf,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[s]=0;
	q.push((node){0,s});
	while(!q.empty()){
		node x=q.top();
		q.pop();
		int u=x.now;
		if(vis[u])continue;
		vis[u]=1;
		for(int i=0;i<p[u].size();i++){
			int v=p[u][i].v;
			if(dis[v]>dis[u]+p[u][i].w){
				dis[v]=dis[u]+p[u][i].w;
				q.push((node){dis[v],v});
			}
		}
	}
}
signed main(){
	int tt;
	cin>>tt;
	for(int rr=1;rr<=tt;rr++){
    	n=read(),m=read(),c=read();
    	for(int i=1;i<=n;i++){
    		layer[i]=read();
    		cs[layer[i]]=1;
		}
		for(int i=1;i<=n;i++){
			p[layer[i]+n].push_back((edge){i,0});
			if(layer[i]-1>=1&&cs[layer[i]-1]==1){
				p[i].push_back((edge){layer[i]-1+n,c});
			}
			if(layer[i]+1<=n&&cs[layer[i]+1]==1){
				p[i].push_back((edge){layer[i]+1+n,c});
			}
		}
    	for(int i=1,x,y,z;i<=m;i++){
        	x=read(),y=read(),z=read();
    		p[x].push_back((edge){y,z});
    		p[y].push_back((edge){x,z});
    	}
    //	cout<<endl<<endl;
    //	for(int i=1;i<=n;i++){
    //		for(int j=0;j<p[i].size();j++){
    //			printf("%d %d %d\n",i,p[i][j].v,p[i][j].w);
	//		}
	//	}
    	dij(1);
    	if(dis[n]==inf)printf("Case #%d: -1\n",rr);
    	else printf("Case #%d: %d\n",rr,dis[n]);
    	memset(layer,0,sizeof(layer));
    	memset(cs,0,sizeof(cs));
    	memset(p,0,sizeof(p));
	}
	return 0;
}

17.HDU 3416 Marriage Match IV

网络流,待补

18.HDU 4370 0 or 1

在这里插入图片描述
这题必须配放个图
此题是我有史以来读过题意最抽象的题目,没有之一,读了两个小时没读懂
题目给了一些条件和一个矩阵,要你求一个矩阵使两个矩阵对应点乘积和最小
思维转化,给出的条件代表点1的出度为1,点n的入度为1,其他的所有点出入度相等,路径长度非负,还有两种特殊情况,图中有从1 or n出发的环,这样的情况下其他的点入度出度全为0,也符合题目的条件
拿dij跑最短路,并判断特殊情况

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,a[305][305],d[305];
const int inf=0x3f3f3f3f;
int ans,h;
int vis[350];
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
void dij(int s){
	memset(d,inf,sizeof(d));
	memset(vis,false,sizeof(vis));
	d[s]=0;
	for(int i=1;i<=n;i++){
		int t=-1;
		for(int j=1;j<=n;j++){
			if(vis[j]==false&&(t==-1||d[t]>d[j])){
				t=j;
			}
		}
		vis[t]=true;
		for(int j=1;j<=n;j++){
			d[j]=min(d[j],d[t]+a[t][j]);
			if(j==s&&t!=s)h=min(h,d[t]+a[t][j]);
		}
	}
} 
int main(){
	while(cin>>n){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				a[i][j]=read();
			}
		}
		h=inf;
		dij(1);
		ans=d[n];
		int t=h;
		h=inf;
		dij(n);
		t+=h;
		cout<<min(ans,t)<<endl;
	}
}

19.POJ 3169 Layout

差分约束模板来了
白书上经典例题
重点在于符号的判断>=和<=是两个方向,并且建立超级源点
建图完跑bellman即可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 200010
#define maxm 200010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,w,cnt,ans;
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
struct edge{
	int u,v,w;
};
vector<edge>e;
int d[1005];
bool bellman(){
	memset(d,inf,sizeof(d));
	d[1]=0;
	for(int i=1;i<n;i++){
		int ok=0;
		for(int j=0;j<e.size();j++){
			edge ee=e[j];
			if(d[ee.v]>d[ee.u]+ee.w){
				d[ee.v]=d[ee.u]+ee.w;
				ok=1;
			}
		}
		if(!ok)break;
	}
	for(int i=0;i<e.size();i++){
		edge ee=e[i];
		if(d[ee.v]>d[ee.u]+ee.w){
			return true;
		}
    }
    return false;
}
signed main(){
	int ml,md;
	n=read(),ml=read(),md=read();
	for(int i=1;i<=ml;i++){
		int u,v,w;
		u=read(),v=read(),w=read();
		e.push_back((edge){u,v,w});
	}
	for(int i=1;i<=md;i++){
		int u,v,w;
		u=read(),v=read(),w=read();
		e.push_back((edge){v,u,-w});
	}
	for(int i=1;i<=n-1;i++){
		e.push_back((edge){i+1,i,0});
	}
	if(bellman())cout<<"-1";
	else{
		if(d[n]>inf/2){
			cout<<"-2";
		}
		else {
			cout<<d[n];
		}
	}
	return 0;
}

由于前天晚上和昨天身体超级难受就慢了一点点…而且最后几个题把我拦住了…所以就花了三天

感觉写一下题解还是挺有用的,真正的理解是能解释给别人听让别人理解(费曼学习法),而且回顾整个专题也可以做一些反思,思考题与题之间的关联和区别,温故知新。

继续保持学习状态,冲!!!

要开始学高数和电路分析了(

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章