能力提升綜合題單 Part 8.4 生成樹&Part 8.5 拓撲排序&Part 8.6 差分約束

1.P3366 【模板】最小生成樹

kruskal

#include<bits/stdc++.h>
using namespace std;
int n,m,a[5005],ans,cnt;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v,w;
}e[200005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+m,cmp);
	for(int i=1;i<=m;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		ans+=e[i].w;
		hb(u,v);
		if(++cnt==n-1)break;
	}
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	for(int i=1;i<=m;i++){
		e[i].u=read();
		e[i].v=read();
		e[i].w=read();
	} 
	krus();
	cout<<ans;
	return 0;
}

prim

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define R register int
using namespace std;

int k,n,m,cnt,sum,ai,bi,ci,head[5005],dis[5005],vis[5005];

struct Edge
{
    int v,w,next;
}e[400005];

void add(int u,int v,int w)
{
    e[++k].v=v;
    e[k].w=w;
    e[k].next=head[u];
    head[u]=k;
}

typedef pair <int,int> pii;
priority_queue <pii,vector<pii>,greater<pii> > q;

void prim()
{
    dis[1]=0;
    q.push(make_pair(0,1));
    while(!q.empty()&&cnt<n)
    {
        int d=q.top().first,u=q.top().second;
        q.pop();
        if(vis[u]) continue;
        cnt++;
        sum+=d;
        vis[u]=1;
        for(R i=head[u];i!=-1;i=e[i].next)
            if(e[i].w<dis[e[i].v])
                dis[e[i].v]=e[i].w,q.push(make_pair(dis[e[i].v],e[i].v));
    }
}

int main()
{
    memset(dis,127,sizeof(dis));
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(R i=1;i<=m;i++)
    {
        scanf("%d%d%d",&ai,&bi,&ci);
        add(ai,bi,ci);
        add(bi,ai,ci);
    }
    prim();
    if (cnt==n)printf("%d",sum);
    else printf("orz");
}

2.P4180 [BJWC2010]嚴格次小生成樹

咕咕咕了

3.P2872 [USACO07DEC]Building Roads S

#include<bits/stdc++.h>
using namespace std;
int n,m,a[5005],cnt,bs=1,qq;
int dis[1005][1005];
double ans;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v;
	double w;
}e[1000005];
struct node{
	double x,y;
}pos[1000005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+bs,cmp);
	for(int i=1;i<=bs;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		ans+=e[i].w;
		hb(u,v);
		if(++cnt==n-1)break;
	}
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	for(int i=1;i<=n;i++){
		pos[i].x=read();
		pos[i].y=read();
	}
	for(int i=1;i<=m;i++){
		int l1,l2;
		l1=read(),l2=read();
		dis[l1][l2]=1;
		dis[l2][l1]=1;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			e[bs].u=i;
			e[bs].v=j;
			e[bs].w=(double)sqrt((pos[i].x-pos[j].x)*(pos[i].x-pos[j].x)+(pos[i].y-pos[j].y)*(pos[i].y-pos[j].y));
			if(dis[i][j]==1){
				e[bs].w=0;
			}
			bs++;
		}
	}
	krus();
	printf("%.2f",ans);
	return 0;
}

4.P1991 無線通訊網

#include<bits/stdc++.h>
using namespace std;
int n,m,a[5005],cnt,bs=1,qq;
int dis[1005][1005];
double ans;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v;
	double w;
}e[1000005];
struct node{
	double x,y;
}pos[1000005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+bs,cmp);
	for(int i=1;i<=bs;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		ans=max(ans,e[i].w);
		hb(u,v);
		if(++cnt==n-m)break;
	}
}
int main(){
	m=read(),n=read();
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	for(int i=1;i<=n;i++){
		pos[i].x=read();
		pos[i].y=read();
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			e[bs].u=i;
			e[bs].v=j;
			e[bs].w=(double)sqrt((pos[i].x-pos[j].x)*(pos[i].x-pos[j].x)+(pos[i].y-pos[j].y)*(pos[i].y-pos[j].y));
			bs++;
		}
	}
	krus();
	printf("%.2f",ans);
	return 0;
}

5.P1967 貨車運輸

這題就跟前面幾個水題不一樣了
先用kruskal求最大生成樹並建新樹,再魔改一下lca(保存兒子到父親路徑的最小權值)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e4+5,maxm=1e5+5;
int f[maxn];
int head[maxn],fa[maxn][22],cnt,dep[maxn],lg[maxm],w[maxn][22],head2[maxn];
int n,m,q;
struct edge{
	int u,v,w,nex;
}e[maxm],e2[maxm];
inline void add(int u,int v,int w){
	e[++cnt].v=v;
	e[cnt].u=u;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt;
}
int cnt2;
inline void add2(int u,int v,int w){
	e2[++cnt2].v=v;
	e2[cnt2].u=u;
	e2[cnt2].w=w;
	e2[cnt2].nex=head2[u];
	head2[u]=cnt2;
}
int find(int x){
	if(x==f[x])return x;
	return f[x]=find(f[x]);
}
void hb(int x,int y){
	int fx=find(x);
	int fy=find(y);
	f[fx]=fy;
}
void dfs(int u,int fath){
	fa[u][0]=fath;
	dep[u]=dep[fath]+1;
	for(int i=1;i<=lg[dep[u]];i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
		w[u][i]=min(w[u][i-1],w[fa[u][i-1]][i-1]);
	}
	for(int i=head2[u];i;i=e2[i].nex){
		if(e2[i].v!=fath){
			w[e2[i].v][0]=e2[i].w;
			dfs(e2[i].v,u);
		}
	}
}
int lca(int x,int y){
	if(find(x)!=find(y))return -1;
	int ans=0x3f3f3f3f;
    if(dep[x]<dep[y])swap(x,y);
	while(dep[x]>dep[y]){
		ans=min(ans,w[x][lg[dep[x]-dep[y]]-1]);
		x=fa[x][lg[dep[x]-dep[y]]-1];
	}
	if(x==y)return ans;
	for(int k=lg[dep[x]]-1;k>=0;k--){
		if(fa[x][k]!=fa[y][k]){
			ans=min(ans,min(w[x][k],w[y][k]));
			x=fa[x][k];
			y=fa[y][k];
		}
	}
	return min(ans,min(w[x][0],w[y][0]));
}
bool cmp(edge x,edge y){
	return x.w>y.w;
}
void krus(){
	sort(e+1,e+1+m,cmp);
	int ans=0;
	for(int i=1;i<=m;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		hb(u,v);
		add2(u,v,e[i].w);
		add2(v,u,e[i].w);
		if(++ans==n)break;
	}
}
int main(){
	cin>>n>>m;
	int u,v,ww;
	for(int i=1;i<=n;i++){
		f[i]=i;
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&u,&v,&ww);
		add(u,v,ww);
	}
	for(int i=1;i<=n;i++){//預先算出log_2(i)+1的值,用的時候直接調用就可以了
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	}
	krus();
	dfs(1,0);
	cin>>q;
	for(int i=1;i<=q;i++){
		scanf("%d%d",&u,&v);
		printf("%d\n",lca(u,v));
	}
	return 0;
}

6.P4047 [JSOI2010]部落劃分

#include<bits/stdc++.h>
using namespace std;
int n,m,a[5005],cnt,bs=1,qq;
int dis[1005][1005];
double ans;
double l,r;
vector<double>g;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v;
	double w;
}e[1000005];
struct node{
	double x,y;
}pos[1000005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp1(edge a,edge b){
	return a.w<b.w;
}
bool cmp2(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+bs,cmp2);
	for(int i=1;i<=bs;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		hb(u,v);
		if(++cnt==n-m+1){
			ans=e[i].w;
			break;
		}
	}
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	for(int i=1;i<=n;i++){
		pos[i].x=read();
		pos[i].y=read();
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			e[bs].u=i;
			e[bs].v=j;
			e[bs].w=(double)sqrt((pos[i].x-pos[j].x)*(pos[i].x-pos[j].x)+(pos[i].y-pos[j].y)*(pos[i].y-pos[j].y));
			bs++;
		}
	}
	sort(e+1,e+1+bs,cmp1);
	for(int i=1;i<=n-m;i++){
		dis[e[i].u][e[i].v]=0;
		e[i].w=0;
	}
	krus();
	printf("%.2f",ans);
	return 0;
}

7.P1113 雜務

小裸拓撲排序,之前學的時候拿這題寫過題解,拓撲排序過程中記錄更新最大時間即可

#include<bits/stdc++.h>
using namespace std;
vector<int>a[10005];
int t[10005];
int s[10005];
int n,m,c,k;
int ru[10005],chu[10005];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		int x,y,z;
		scanf("%d %d",&x,&t[i]);
		s[i]=t[i];
		while(1){
			cin>>z;
			a[x].push_back(z);
			ru[z]++;
			if(z==0)break;
		}
	}
	queue<int>q;
	for(int i=1;i<=n;i++){
		if(!ru[i]){
			q.push(i);
		}
	}
	while(!q.empty()){
		int v=q.front();
		q.pop();
		for(int i=0;i<a[v].size();i++){
			ru[a[v][i]]--;
			s[a[v][i]]=max(s[a[v][i]],s[v]+t[a[v][i]]);
			if(ru[a[v][i]]==0){
				q.push(a[v][i]);
			}
		}
	}
	for(int i=1;i<=n;i++){
		c=max(c,s[i]);
	}
	cout<<c;
	return 0;
}

8.P1983 車站分級

對於一趟車,起始中每一個不停的站點的等級都是低於路途中停下來的站點,記錄下來,讀入完畢之後進行拓撲排序,記錄最大等級即可

#include<bits/stdc++.h>
using namespace std;
vector<int>a[1005],st[1005];
bool lian[1005][1005];
int ru[1005];
int n,m,c,ans,s;
int t[1005],den[1005];
int main(){
	cin>>n>>m;
//	memset(lian,false,sizeof(lian));
	for(int i=1;i<=m;i++){
		memset(t,0,sizeof(t));
		int x,y;
		scanf("%d",&x);
		for(int j=1;j<=x;j++){
			scanf("%d",&y);
			t[y]++;
			st[i].push_back(y);
		}
		for(int j=0;j<st[i].size();j++){
			for(int k=st[i][0];k<=st[i][x-1];k++){
				if(t[k]==0&&lian[k][st[i][j]]==false){
					a[k].push_back(st[i][j]);
					ru[st[i][j]]++;
					lian[k][st[i][j]]=true;
				}
			}
		}
		
	}
	queue<int>q;
	for(int i=1;i<=n;i++){
		if(ru[i]==0){
			q.push(i);
			den[i]=1;
		}
	}
	while(q.size()!=0){
		int now=q.front();
		q.pop();
		for(int i=0;i<a[now].size();i++){
			ru[a[now][i]]--;
			if(ru[a[now][i]]==0){
				q.push(a[now][i]);
				den[a[now][i]]=den[now]+1;
			}
		}
	}
	for(int i=1;i<=n;i++){
		ans=max(ans,den[i]);
	}
	cout<<ans;
	return 0;
}

9.P1038 神經網絡

題意擱這逼逼賴賴,其實就是裸拓撲排序

#include<bits/stdc++.h>
using namespace std;
const int maxn=205,maxm=20005;
int n,p,c[maxn],head[maxn],cnt,vis[maxn],chu[maxn];
struct edge{
	int v,w,nex;
}e[maxm];
inline void add(int u,int v,int w){
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt;
}
int main(){
	cin>>n>>p;
	int x,y;
	queue<int>q;
	for(int i=1;i<=n;i++){
		cin>>c[i]>>y;
		if(c[i]){
			q.push(i);
			vis[i]=1;
		}
		else{
			c[i]-=y;
		}
	}
	int u,v,w;
	for(int i=1;i<=p;i++){
		cin>>u>>v>>w;
		add(u,v,w);
		chu[u]=1;
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		if(c[u]<=0)continue;
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].v;
			c[v]+=e[i].w*c[u];
			if(!vis[v]){
				q.push(v);
				vis[v]=1;
			}
		}
	}
	int f=0;
	for(int i=1;i<=n;i++){
		if(chu[i]==0&&c[i]>0){
			printf("%d %d\n",i,c[i]);
			f=1;
		}
	}
	if(f==0)puts("NULL");
	return 0;
}

10.P5960 【模板】差分約束算法

套公式,建源點

#include<bits/stdc++.h>
using namespace std;
const int maxm=10005;
struct edge{
	int v,w,nex;
}e[maxm];
int head[maxm],dis[maxm],inq[maxm],cnt,n,m,cs[maxm];
inline void add(int u,int v,int w){
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt;
}
bool spfa(int s){
	queue<int>q;
	memset(dis,0x3f,sizeof dis);
	dis[s]=0;
	inq[s]=1;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		inq[u]=0;
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].v;
			if(dis[v]>dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				if(!inq[v]){
					q.push(v);
					cs[v]++;
					if(cs[v]==n)return true;
				}
			}
		}
	}
	return false;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		add(0,i,0);
	}
	int u,v,w;
	for(int i=1;i<=m;i++){
		cin>>u>>v>>w;//不等式:  u-v<=w 
		add(v,u,w);
	}
	if(spfa(0))puts("NO");
	else{
		for(int i=1;i<=n;i++){
			cout<<dis[i]<<" ";
		}
	}
	return 0;
}

11.P3275 [SCOI2011]糖果

對五種情況進行套公式即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=4e5+5;
struct edge{
	int v,w,nex;
}e[maxm];
int head[maxm],dis[maxm],inq[maxm],cnt,n,m,cs[maxm];
inline void add(int u,int v,int w){
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt;
}
bool spfa(int s){
	queue<int>q;
	memset(dis,-0x3f,sizeof dis);
	dis[s]=0;
	inq[s]=1;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		inq[u]=0;
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].v;
			if(dis[v]<dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				if(!inq[v]){
					q.push(v);
					cs[v]++;
					if(cs[v]==n)return true;
				}
			}
		}
	}
	return false;
}
signed main(){
	cin>>n>>m;
	for(int i=n;i>=1;i--){
		add(0,i,1);
	}
	int x,a,b;
	int fafa=0;
	for(int i=1;i<=m;i++){
		scanf("%lld%lld%lld",&x,&a,&b);
		if(x==1){
			add(b,a,0);
			add(a,b,0);
		}
		else if(x==2){
			add(a,b,1);
		}
		else if(x==4){
			add(b,a,1);
		}
		else if(x==3){
			add(b,a,0);
		}
		else if(x==5){
			add(a,b,0);
		}
		if(x%2==0&&a==b){
			fafa=1;
		}
	}
	if(fafa==1){
		puts("-1");
		return 0;
	}
	long long ans=0;
	int tt=-1e18+5;
	if(spfa(0)){
	    puts("-1");
	    return 0; 
	} 
	else{
		for(int i=1;i<=n;i++){
			ans+=dis[i];
		}
	}
	cout<<ans;
	return 0;
}

12.P2294 [HNOI2005]狡猾的商人

有環即爲false,不要建源點

#include<bits/stdc++.h>
using namespace std;
const int maxm=4e5+5;
struct edge{
	int v,w,nex;
}e[maxm];
int head[maxm],dis[maxm],inq[maxm],cnt,n,m,cs[maxm];
inline void add(int u,int v,int w){
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt;
}
bool spfa(int s){
	queue<int>q;
	memset(dis,0x3f,sizeof dis);
	memset(inq,0,sizeof(inq));
	memset(cs,0,sizeof(cs));
	dis[s]=0;
	inq[s]=1;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		inq[u]=0;
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].v;
			if(dis[v]>dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				if(!inq[v]){
					q.push(v);
					cs[v]++;
					if(cs[v]==n)return true;
				}
			}
		}
	}
	return false;
}
inline void init(){
	memset(head,0,sizeof head);
	cnt=0;
}
signed main(){
	int tt;
	cin>>tt;
	int s,t,w;
	while(tt--){
		cin>>n>>m;
		init();
		for(int i=1;i<=m;i++){
			cin>>s>>t>>w;
			add(s-1,t,w);
			add(t,s-1,-w);
		}
    	if(!spfa(0))printf("true\n");
    	else printf("false\n");
	}
    return 0;
}

13.P4926 [1007]倍殺測量者

咕咕咕

14.P5590 賽車遊戲

咕咕咕

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