玄关抓虫,非常着急
查看原帖
玄关抓虫,非常着急
367897
yuzh2005楼主2024/3/9 15:34

60pts,WA#4,5,6,9,10,无TLE

大致原理:第一问EK算法最大流,第二问在1的基础上每个边权乘以一个常量并+1,用1的微差比较边数,且不影响最终结果;

问题代码见下:

#include<bits/stdc++.h>
#define N 0x7f7f7f7f7f
using namespace std;
long long C1[500][500];
bool visit[500],cata[500][500];
int pre[1001];
int n,m,t=0;//n点m边 
long long int ans=0;
inline bool bfs(){
	memset(visit,0,sizeof(visit));
	memset(pre,0,sizeof(pre));
	visit[1]=1;
	pre[1]=0;//此处的0作为回溯终止的标记 
	queue<int> q;
	q.push(1);
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(int i=1;i<=n+t;i++){
			if(!visit[i]&&C1[x][i]>0){
				pre[i]=x;//边走边记路径
				if(i==n) return 1;
				else{
					visit[i]=1;
					q.push(i); 
				}
			}
		}
	} 
	return 0;
}
inline void giao(){
	while(bfs()){
		long long ton=N;
		for(int i=n;pre[i]!=0;i=pre[i]){
			ton=min(ton,C1[pre[i]][i]);
		}
		for(int i=n;pre[i]!=0;i=pre[i]){
			C1[pre[i]][i]-=ton;
			C1[i][pre[i]]+=ton;
		}
		ans+=ton;
		continue;
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int a,b,c;
		cin>>a>>b>>c;
		C1[a][b]+=c; 
	}
	for(int i=1;i<=n;i++){//本输入不能处理给定的双向边,所以要通过加点的方式把双向边a←→b处理成a→b,a←c←b,使之不干扰EK算法的工作原理 
		for(int j=1;j<=n&&j!=i;j++){
			if((C1[i][j]>0)&&(C1[j][i]>0)){
				t++;
				C1[j][n+t]=C1[j][i];
				C1[n+t][i]=C1[j][i];
				C1[j][i]=0;
			}
		}
	}
	for(int i=1;i<=n+t;i++){
		for(int j=1;j<=n+t;j++){
			if(C1[i][j]>0){
				C1[i][j]=C1[i][j]*32767+1;//稳流法,用乘大数的方式统一最大流相同时的情况,用加一来区分割边数 
			}
		}
	}
	giao();
	cout<<ans/32767<<" "<<ans%32767;
	return 0;
} 
2024/3/9 15:34
加载中...