【Q - Marriage Match IV】

80 篇文章 0 订阅
80 篇文章 0 订阅

思路:

  • 最短路找出允许走的路,然后跑一遍网络流找出从源点到汇点有多少流量。
  • Dijkstra,Dinic(Edmonds-Karp会TLE)。
  • (第一道网络流,后续会写总结。)

最短路提取://to do

代码:

  • Dijkstra+Edmonds-Karp:TLE
#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
#include <cstdio>
#define INF 0x3f3f3f3f
//邻接矩阵没法存储重边 
//邻接表求求你检查 int v = E[i].to;
using namespace std;

const int maxn = 1005;

int T;
int N,M;
int U,V;
int C[maxn][maxn];
int F[maxn];
int ANS;
int dis[maxn];

struct EDGE{
	int to;
	int w;
	int fo;
}E[maxn * 100] ; int cnt;
int tail[maxn];
void ADDEDGE(int u,int v,int w){
	++cnt;
	E[cnt].to = v;
	E[cnt].w = w;
	E[cnt].fo = tail[u];
	tail[u] = cnt;
}

struct NODE{
	int id;
	int dis;
	NODE(int id,int dis) : id(id) , dis(dis) {} ;
	friend bool operator > (NODE a,NODE b){
		return a.dis > b.dis;
	}
};
priority_queue<NODE , vector<NODE> , greater<NODE> > Q;

void INIT(){
	memset(tail,-1,sizeof(tail));
	memset(dis , INF , sizeof(dis));
	cnt = 0;
	ANS = 0;
	return ;
}

void IJK(){
	Q.push(NODE(U,0));dis[U] = 0;
	while(Q.size()){
		NODE cur = Q.top() ; Q.pop();
		if(dis[cur.id] < cur.dis)
			continue;
		for(int i=tail[cur.id] ; ~i ; i=E[i].fo){
			int v = E[i].to;
			if(dis[v] > dis[cur.id] + E[i].w){
				dis[v] = dis[cur.id] + E[i].w;
				Q.push(NODE(v,dis[v]));
			}
		}
	}
	//通过最短路得到最短路网络,使用的是 "某条小径属于网络" 的必要条件,因此会有许多不能到汇点的边,但是实现简单。 
	memset(C,0,sizeof(C));
	for(int u=1;u<=N;u++){
		for(int i=tail[u] ; ~i ; i=E[i].fo){
			if(dis[E[i].to] == dis[u] + E[i].w)
				C[u][E[i].to] += 1;
		} 
	}
	return ;
}

queue<int> q;
int pre[maxn];
int BFS(){
	memset(F,0,sizeof(F));
	memset(pre,0,sizeof(pre));
	while(q.size())
		q.pop();
	q.push(U);F[U] = INF;//vital
	while(q.size()){
		int cur = q.front();q.pop();
		if(cur == V)
			break;//not clear
		for(int i=tail[cur] ; ~i ; i=E[i].fo){
			int v = E[i].to;
			if(C[cur][v] > 0 && !pre[v]){
				F[v] = min(F[cur] , C[cur][v]);
				pre[v] = cur;
				q.push(v);//仅将有用的入队 
			}
		}
	}
	if(!pre[V])
		return 0;
	else
		return F[V];
}

void Edmonds_Karp(){
	int increasement;
	while(increasement = BFS()){
		int i = V;
		while(pre[i]){
			C[pre[i]][i] -= increasement;
			C[i][pre[i]] += increasement;
			i = pre[i];
		}
		ANS += increasement;
	}
	return ;
}

int main(){
	scanf("%d",&T);
	while(T--){
		INIT();
		scanf("%d%d",&N,&M);
		for(int i=1;i<=M;i++){
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			if(u == v)
				continue;//not clear
			ADDEDGE(u,v,w);
		}
		scanf("%d%d",&U,&V);
		IJK();
		Edmonds_Karp();
		printf("%d\n",ANS);
	}
	return 0;
}
  • Dijkstra+Dinic:202ms 6568kB
//202ms		6568kB


#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
#include <cstdio>
#define INF 0x3f3f3f3f
//邻接矩阵没法存储重边 
//邻接表求求你检查 int v = E[i].to;
using namespace std;

const int maxn = 1005;

int T;
int N,M;
int U,V;
int C[maxn][maxn];
int F[maxn];
int ANS;
int dis[maxn];

struct EDGE{
	int to;
	int w;
	int fo;
}E[maxn * 100] ; int cnt;
int tail[maxn];
void ADDEDGE(int u,int v,int w){
	++cnt;
	E[cnt].to = v;
	E[cnt].w = w;
	E[cnt].fo = tail[u];
	tail[u] = cnt;
}

struct NODE{
	int id;
	int dis;
	NODE(int id,int dis) : id(id) , dis(dis) {} ;
	friend bool operator > (NODE a,NODE b){
		return a.dis > b.dis;
	}
};
priority_queue<NODE , vector<NODE> , greater<NODE> > Q;

void INIT(){
	memset(tail,-1,sizeof(tail));
	cnt = 0;
	ANS = 0;
	return ;
}

void IJK(){
	memset(dis , INF , sizeof(dis));
	Q.push(NODE(U,0));dis[U] = 0;
	while(Q.size()){
		NODE cur = Q.top() ; Q.pop();
		if(dis[cur.id] < cur.dis)
			continue;
		for(int i=tail[cur.id] ; ~i ; i=E[i].fo){
			int v = E[i].to;
			if(dis[v] > dis[cur.id] + E[i].w){
				dis[v] = dis[cur.id] + E[i].w;
				Q.push(NODE(v,dis[v]));
			}
		}
	}
	//通过最短路得到最短路网络,使用的是 "某条小径属于网络" 的必要条件,因此会有许多不能到汇点的边,但是实现简单。 
	memset(C,0,sizeof(C));
	for(int u=1;u<=N;u++){
		for(int i=tail[u] ; ~i ; i=E[i].fo){
			if(dis[E[i].to] == dis[u] + E[i].w)
				C[u][E[i].to] += 1;
		} 
	}
	return ;
}

int deep[maxn];
queue<int> q;
bool BFS(){
	memset(deep,-1,sizeof(deep));
	q.push(U);deep[U]=0;
	while(q.size()){
		int cur = q.front() ; q.pop() ;
		for(int i=1;i<=N;i++){
			if(C[cur][i] > 0 && !~deep[i]){
				//尚有用 
				//是-1,即没见过,则加入队列 
				q.push(i);
				deep[i] = deep[cur] + 1;
			}
		}
	}
	if(~deep[V])
		return true;
	return false;
}

int DFS(int u,int maxflow){
	if(u == V)
		return maxflow;
	for(int i=1;i<=N;i++){
		if(C[u][i] > 0 && deep[i] == deep[u] + 1){
			int result = DFS(i , min(maxflow , C[u][i]));
			if(result){
				C[u][i] -= result;
				C[i][u] += result;
				return result;
			}
		}
	}
	return 0;
}

void DINIC(){
	while(BFS()){
		while(true){
			int aug = DFS(U,INF);
			if(!aug) break;
			ANS += aug;
		}
	}
	return ;
}

int main(){
	scanf("%d",&T);
	while(T--){
		INIT();
		scanf("%d%d",&N,&M);
		for(int i=1;i<=M;i++){
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			if(u == v)
				continue;//not clear
			ADDEDGE(u,v,w);
		}
		scanf("%d%d",&U,&V);
		IJK();
		DINIC();//Dinitz 
		printf("%d\n",ANS);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值