Day1 最短路專題

~hsm~發表於2019-02-26

A. POJ 3660 Cow Contest 傳遞閉包

題目

POJ3660

題解

這個。。。。。。不需要題解吧。

程式碼

//#include<bits/stdc++.h>
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=110;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1,ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
int d[maxn][maxn],ans;
int main()
{
	int n,m;read(n);read(m);
	for (int i=1;i<=m;++i)
	{
		int x,y;
		read(x);read(y);
		d[x][y]=1;
	}
	for (int k=1;k<=n;++k)
		for (int i=1;i<=n;++i)
			for (int j=1;j<=n;++j)
				d[i][j]|=d[i][k]&d[k][j];
	for (int i=1;i<=n;++i)
	{
		int tot=0;
		for (int j=1;j<=n;++j)
			if (d[i][j] || d[j][i])
				++tot;
		if (tot==n-1) ++ans;
	}
	printf("%d\n",ans);
	return 0;
}

B. UVA11374 Airport Express

題目

LUOGU UVA11374

程式碼(AC)

#include<bits/stdc++.h>
using namespace std;
const int maxn=505,maxm=5005;
const int inf=0x3f3f3f3f;
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1,ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
int n,s,t;
int ver[maxn*maxm],edge[maxn*maxm],Next[maxn*maxm],head[maxn],len;
inline void add(int x,int y,int z)
{
    ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
int vis[maxn],dist[2][maxn],pre[2][maxn];
inline void spfa(int flag)
{
    queue<int>q;
    for (int i=1;i<=n;++i)
    {
        dist[flag][i]=inf;
        vis[i]=0;
        pre[flag][i]=-1;
    }
    dist[flag][s]=0,vis[s]=1;
    pre[flag][s]=s,q.push(s);
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=0;
        for (int i=head[x];i;i=Next[i])
        {
            int y=ver[i],z=edge[i];
            if (dist[flag][y]>dist[flag][x]+z)
            {
                dist[flag][y]=dist[flag][x]+z;
                pre[flag][y]=x;
                if (!vis[y]) q.push(y),vis[y]=1;
            }
        }
    }
}
inline void input()
{
    int num;
    read(num);
    for (int i=1;i<=num;++i)
    {
        int a,b,c;
        read(a);read(b);read(c);
        add(a,b,c),add(b,a,c);
    }
}
inline void print(int x)
{
    if (pre[0][x]==x)
    {
        printf("%d",x);//多打了個空格 
        return ;
    }
    print(pre[0][x]);
    printf(" %d",x);
}
inline void solve()
{
    int num,minum=dist[0][s],tu=-1,tv=-1;
    read(num);
    for (int i=1;i<=num;++i)
    {
        int a,b,c;
        read(a);read(b);read(c);
        if (dist[0][a]+dist[1][b]+c<minum)
        {
            minum=dist[0][a]+dist[1][b]+c;
            tu=a,tv=b;
        }
        if (dist[0][b]+dist[1][a]+c<minum)
        {
            minum=dist[0][b]+dist[1][a]+c;
            tu=b,tv=a;
        }
    }
    if (tu==-1)
    {
        print(s);
        puts("");
        puts("Ticket Not Used");
    }
    else
    {
        print(tu);
        for (int i=tv;i!=s;i=pre[1][i])
            printf(" %d",i);//打成了printf(" %d,i");好無語
        printf(" %d\n",s);
        printf("%d\n",tu);
    }
    printf("%d\n",minum);
}
int main()
{
    int cnt=1;
    while (scanf("%d %d %d",&n,&s,&t)==3)
    {
        memset(head,0,sizeof(head));
        if (cnt!=1) puts("");
        ++cnt;
        input();
        spfa(0);
        s=t;
        spfa(1);
        solve();
    }
    return 0;
}

C.BZOJ 4152: [AMPPZ2014]The Captain

題目

BZOJ 4152

題解

先說下做法:
1.對於一個點,我們記錄他的位置idid,橫座標c,縱座標yy
2.先將點的橫座標xx從小到大排序,然後每兩個點建圖,然後縱座標yy亦然。
3.跑一遍heap+dijkstraheap+dijkstra模板,輸出dist[n]dist[n]即可。

程式碼

//#include<bits/stdc++.h>
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
#define pii pair<long long,int>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
struct Orz
{
	int id,x,y;
}h[maxn];
inline bool mycpy1(Orz a,Orz b)
{
	return a.x<b.x;
}
inline bool mycpy2(Orz a,Orz b)
{
	return a.y<b.y;
}
int ver[maxn<<2],Next[maxn<<2],head[maxn],len;
ll edge[maxn<<2];
inline void add(int x,int y,int z)
{
	ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
ll dist[maxn];
bool vis[maxn];
inline void dijkstra_heap(int s)
{
	memset(dist,0x3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	priority_queue<pii,vector<pii>,greater<pii> >q;
	dist[s]=0;
	q.push(make_pair(0,s));
	while (!q.empty())
	{
		int x=q.top().second;
		q.pop();
		if (vis[x]) continue;
		vis[x]=1;
		for (int i=head[x];i;i=Next[i])
		{
			int y=ver[i],z=edge[i];
			if (dist[y]>dist[x]+z)
			{
				dist[y]=dist[x]+z;
				q.push(make_pair(dist[y],y));
			}
		}
	}
}
int main()
{
	int n;read(n);
	for (int i=1;i<=n;++i)
		read(h[i].x),read(h[i].y),h[i].id=i;
	sort(h+1,h+n+1,mycpy1);
	for (int i=1;i<n;++i)
		add(h[i].id,h[i+1].id,h[i+1].x-h[i].x),add(h[i+1].id,h[i].id,h[i+1].x-h[i].x);
	sort(h+1,h+n+1,mycpy2);
	for (int i=1;i<n;++i)
		add(h[i].id,h[i+1].id,h[i+1].y-h[i].y),add(h[i+1].id,h[i].id,h[i+1].y-h[i].y);
	dijkstra_heap(1);
	printf("%lld\n",dist[n]);
	return 0;
}

D. UVA10603 倒水問題 Fill

題目

LUOGU UVA10603

題解

首先由於沒有刻度,如果用數學方法計算,不好算,樣例還好算一點,我們觀察那個abca,b,c都不大於200200,挺小的,適合暴力求解。

就是把所有情況都倒一次,倒水就兩種倒法,要麼把一個杯子倒滿,要麼就是這個杯子空了,由於水量是固定的,那麼確定兩個杯子的水量,那麼第三個也就確定了,所以我們用二維陣列進行標記,我記的是前兩個杯子(記任意兩個都行)。

由於要求是倒水題最少,而不是步數最少,首先它們沒有必要的關係,並不是步數少,倒水題就少,所以我們採用優先佇列,倒水量少的優先,那麼倒到dd時,倒水量一定是最少的,

然後就是BFSBFS,把所有的情況都找一下,如果找到及時退出,找不到找比dd小並且最近的即可。

注意標記的時候,不要標記錯,我第一次標記錯了,不是標記iji,j,而是固定的數。

摘自dwtfukgv

程式碼

#include<bits/stdc++.h>
using namespace std;
const int maxn=205;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
struct orz
{
	int val[3],d;
	bool operator < (const orz &tmp) const
	{
		return d>tmp.d;
	}
};
int ans[maxn];
bool vis[maxn][maxn];
inline void update(orz x)//及時更新倒水量
{
	for (int i=0;i<3;++i)
	{
		int y=x.val[i];
		if (ans[y]<0 || ans[y]>x.d) ans[y]=x.d;
	}
}
inline void bfs(int a,int b,int c,int d)
{
	int cap[]={a,b,c};//容量大小
	memset(ans,-1,sizeof(ans));
	memset(vis,0,sizeof(vis));
	priority_queue<orz>q;
	orz x;
	x.val[0]=0,x.val[1]=0;//開始的狀態
	x.val[2]=c,x.d=0;
	q.push(x);
	vis[0][0]=1;

	while (!q.empty())
	{
		x=q.top();
		q.pop();
		update(x);
		if (ans[d]>=0) break;//找到d了 及時退出

		for (int i=0;i<3;++i)
			for (int j=0;j<3;++j)
			{
				if (i==j || !x.val[i] || x.val[j]==cap[j]) continue;//i是空的,或者j是已經滿了

				orz y;
				memcpy(&y,&x,sizeof(x));
				int t=min(cap[j]-y.val[j],y.val[i]);//找倒水量,要麼倒滿,要麼倒空
				y.val[i]-=t;
				y.val[j]+=t;
				y.d+=t;
				if (vis[y.val[0]][y.val[1]]) continue;
				vis[y.val[0]][y.val[1]]=1;
				q.push(y);
			}
	}
	
	for ( ;d>=0;--d)//找最近的
		if (ans[d]>=0)
		{
			printf("%d %d\n",ans[d],d);
			return ;
		}
	
}
int main()
{
	int t;read(t);
	while (t--)
	{
		int a,b,c,d;
		read(a);read(b);
		read(c);read(d);
		bfs(a,b,c,d);
	}
	return 0;
}

E. BZOJ 2662: [BeiJing wc2012]凍結 分層圖

題目

BZOJ 2662
LUOGU 4822

錯誤原因

在這裡插入圖片描述
兩份程式碼唯一的不同就是maxn的大小,AC的maxn是1e6+10,TLE的maxn是1e7+10。

程式碼

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1,ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
int ver[maxn<<1],edge[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y,int z)
{
	ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
int dist[maxn];
bool vis[maxn];
inline void spfa(int s)
{
	memset(dist,0x3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	queue<int>q;
	dist[s]=0,vis[s]=1;
	q.push(s);
	while (!q.empty())
	{
		int x=q.front();
		q.pop();
		vis[x]=0;
		for (int i=head[x];i;i=Next[i])
		{
			int y=ver[i],z=edge[i];
			if (dist[y]>dist[x]+z)
			{
				dist[y]=dist[x]+z;
				if (!vis[y]) q.push(y),vis[y]=1;
			}
		}
	}
}
int main()
{
	int n,m,k;
	read(n);read(m);read(k);
	for (int i=1;i<=m;++i)
	{
		int x,y,z;
		read(x);read(y);read(z);
		add(x,y,z);add(y,x,z);
		for (int j=0;j<=k;++j)
		{
			add(x+j*n,y+j*n,z);
			add(y+j*n,x+j*n,z);
			add(x+j*n,y+(j+1)*n,z>>1);
			add(y+j*n,x+(j+1)*n,z>>1);
		}
	}
	spfa(1);
	int ans=0x3f3f3f3f;
	for (int i=0;i<=k;++i)
		ans=min(ans,dist[n*(i+1)]);
	printf("%d\n",ans);
	return 0;
}

雙倍經驗:

BZOJ 2763: [JLOI2011]飛行路線

BZOJ 2763
LUOGU 4568

錯誤原因

在這裡插入圖片描述
陣列範圍真是一門學問,開大了還會TLE。。。。。。。。。

程式碼

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int maxn=11e4+10,maxm=125e4+10;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1,ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
int ver[maxm<<1],edge[maxm<<1],Next[maxm<<1],head[maxn],len;
inline void add(int x,int y,int z)
{
	ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
int dist[maxn];
bool vis[maxn];
inline void Dijkstra(int s)
{
	memset(dist,0x3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	priority_queue<pii,vector<pii>,greater<pii> >q;
	dist[s]=0;
	q.push(make_pair(0,s));
	while (!q.empty())
	{
		int x=q.top().second;
		q.pop();
		if (vis[x]) continue;
		vis[x]=1;
		for (int i=head[x];i;i=Next[i])
		{
			int y=ver[i],z=edge[i];
			if (dist[y]>dist[x]+z)
			{
				dist[y]=dist[x]+z;
				q.push(make_pair(dist[y],y));
			}
		}
	}
}
int main()
{
	int n,m,k,st,ed;
	read(n);read(m);read(k);
	read(st);read(ed);
	for (int i=1;i<=m;++i)
	{
		int x,y,z;
		read(x);read(y);read(z);
		add(x,y,z);add(y,x,z);
		for (int j=1;j<=k;++j)
		{
			add(x+(j-1)*n,y+j*n,0);//相當於使用了一個卡片,從這一層向另一層連一條邊
			add(y+(j-1)*n,x+j*n,0);
			add(x+j*n,y+j*n,z);
			add(y+j*n,x+j*n,z);
		}
	}
	for (int i=1;i<=k;++i)
		add(ed+(i-1)*n,ed+i*n,0);
	Dijkstra(st);
	printf("%d\n",dist[ed+k*n]);
	return 0;
}

三倍經驗

[USACO09FEB]改造路Revamping Trails

LUOGU 2939

程式碼

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int maxm=21e5+10,maxn=22e4+10;
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1,ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
int ver[maxm<<1],edge[maxm<<1],Next[maxm<<1],head[maxn],len;
inline void add(int x,int y,int z)
{
    ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
int dist[maxn];bool vis[maxn];
inline void Dijkstra(int s)
{
	memset(dist,0x3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	priority_queue<pii,vector<pii>,greater<pii> >q;
	dist[s]=0;
	q.push(make_pair(0,s));
	while (!q.empty())
	{
		int x=q.top().second;
		q.pop();
		if (vis[x]) continue;
		vis[x]=1;
		for (int i=head[x];i;i=Next[i])
		{
			int y=ver[i],z=edge[i];
			if (dist[y]>dist[x]+z)
			{
				dist[y]=dist[x]+z;
				q.push(make_pair(dist[y],y));
			}
		}
	}
}
int main()
{
    int n,m,k;
	read(n);read(m);read(k);
    for (int i=1;i<=m;++i)
    {
        int x,y,z;
        read(x);read(y);read(z);
        add(x,y,z);add(y,x,z);
        for (int j=1;j<=k;++j)
        {
        	add(x+j*n,y+j*n,z);
            add(y+j*n,x+j*n,z);
            add(x+(j-1)*n,y+j*n,0);
            add(y+(j-1)*n,x+j*n,0);
		}
    }
    int tmp=n;
    Dijkstra(1);
	int ans=dist[tmp];
    for (int i=1;i<=k;++i)
        ans=min(ans,dist[n*i+tmp]);
    printf("%d\n",ans);
    return 0;
}

F. BZOJ 2118 墨墨的等式 數論建圖

題目

BZOJ 2118
LUOGU 2371

題解

首先,隆重推出這位大佬BerryKanryTyouchieTyouchie大佬看後都說這位講的不錯,所以,題解什麼的,就省略了。。

程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1,ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
int n;
ll ql,qr,maxmum=0x3f3f3f3f3f3f3f3fll;
ll a[maxn],dist[maxn],vis[maxn];
inline void spfa()
{
	memset(dist,0x3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	queue<int>q;
	dist[0]=0,vis[0]=1;
	q.push(0);
	while (!q.empty())
	{
		int x=q.front();
		q.pop();
		vis[x]=0;
		for (int i=1;i<=n;++i)
		{
			int y=(x+a[i])%maxmum;
			if (dist[y]>dist[x]+a[i])
			{
				dist[y]=dist[x]+a[i];
				if (!vis[y]) q.push(y),vis[y]=1;
			}
		}
	}
}
inline ll query(ll x)
{
	ll ans=0;
	for (int i=0;i<maxmum;++i)
		if (dist[i]<=x)
			ans+=(x-dist[i])/maxmum+1;
	return ans;
}
int main()
{
	read(n);read(ql);read(qr);
	for (int i=1;i<=n;++i)
	{
		read(a[i]);
		if (!a[i])
		{
			--i,--n;
			continue;
		}
		maxmum=min(maxmum,a[i]);
	}
	spfa();
	printf("%lld\n",query(qr)-query(ql-1));
	return 0;
}

相關文章