刷題記錄 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;
}

由於前天晚上和昨天身體超級難受就慢了一點點…而且最後幾個題把我攔住了…所以就花了三天

感覺寫一下題解還是挺有用的,真正的理解是能解釋給別人聽讓別人理解(費曼學習法),而且回顧整個專題也可以做一些反思,思考題與題之間的關聯和區別,溫故知新。

繼續保持學習狀態,衝!!!

要開始學高數和電路分析了(

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