poj 1815 Friendship

本文介绍了一种使用最大流算法解决特定图论问题的方法:通过修改有向图并利用最大流算法来确定最少需要删除哪些节点才能断开源点到终点的路径。文章详细解释了算法的具体实现过程,并提供了一个完整的C++代码示例。

题目大意:求一个有向图删除多少的点,使得源点到终点不连通

解题思路:最大流,拆点和枚举

每个点拆成两个点,这两个点之间的容量为1,源点和终点拆成的点容量为无穷大,

当一个点和另一个点有边时,假设是i和j两个点, 那么i拆成两个点i, i',j拆成两个点j, j', i'和j连接,容量为无穷大

然后枚举除源点,和终点的每个点,删除这个点,看容量是否减少,减少则为要删除的点。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits> 
#include <queue>
using namespace std;

const int maxn = 210;
const int maxm = 10010;

struct node
{
    int u, v, cap, flow, next; 
};

int n, e, s, t, tot, graph[maxn][maxn], head[2 * maxn], cur[2 * maxn], height[2 * maxn], cnt[2 * maxn], store[2 * maxn], path[2 * maxn];
int tt[2][maxn];
 
node edge[maxm + 4 * maxn]; 
 
void addEdge(int u, int v, int val);
int sap();
void build();



int main()
{
        while(scanf("%d %d %d", &n, &s, &t) != EOF)
    {
        s--; t--;
        bool flag = false; 
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
				scanf("%d", &graph[i][j]);
        }
        if(graph[s][t] == 1)
        {
            printf("NO ANSWER!\n");
            continue; 
        }
        build();
		int ans = sap();
		printf("%d\n", ans);
		if(ans == 0)
			continue;
		for(int i = 0; i < n; i++)
		{
			if(i == s || i == t)
				continue;
			
			for(int j = 0; j < n; j++)
			{
				tt[0][j] = graph[i][j];
				tt[1][j] = graph[j][i];
				graph[i][j] = 0;
				graph[j][i] = 0;
			}
			build();
			int tmp = sap();
			if(tmp < ans)
			{
				ans--;
				printf("%d ", i + 1);
			}
			else
			{
				for(int j = 0; j < n; j++)
				{
					graph[i][j] = tt[0][j];
					graph[j][i] = tt[1][j];
				}
			}
				
			if(tmp == 0)
				break;
		} 
		printf("\n");
    } 
      return 0;
}

void addEdge(int u, int v, int val)
{
    edge[e].u = u;
    edge[e].v = v;
    edge[e].cap = val;
    edge[e].flow = 0;
    edge[e].next = head[u];
    head[u] = e++; 
    
    edge[e].u = v;
    edge[e].v = u;
    edge[e].cap = 0;
    edge[e].flow = 0;
    edge[e].next = head[v];
    head[v] = e++;
} 

void build()
{
	memset(head, -1, sizeof(head));
	e = 0;
	for(int i = 0; i < n; i++)
	{
        for(int j = 0; j < n; j++)
        {
			if(i == j)
			{
				if(i == s || i == t)
            		addEdge(i, i + n, INT_MAX);
        		else
            		addEdge(i, i + n, 1);
			}
			else if(graph[i][j] == 1)
				addEdge(i + n, j, INT_MAX);
		}
	}
}

int sap()
{
    int ans = 0, u, v, now;
    memset(height, 0, sizeof(height));
    memset(cnt, 0, sizeof(cnt));
    cnt[0] = 2 * n;
    for(int i = 0; i < 2 * n; i++)
        cur[i] = head[i];
    store[s] = INT_MAX;
    u = s; 
    while(height[s] < 2 * n)
    {
        for(now = cur[u]; now != -1; now = edge[now].next)
        {
            v = edge[now].v;
            if(edge[now].cap != edge[now].flow && height[u] == height[v] + 1)
                break; 
        }
        if(now != -1)
        {
			cur[u] = now;
			path[v] = now;
			store[v] = min(store[u], edge[now].cap - edge[now].flow);
			u = v;
			if(u == t)
			{
				while(u != s)
				{
					edge[path[u]].flow += store[t];
					edge[path[u] ^ 1].flow -= store[t];
					u = edge[path[u]].u;
				}
				ans += store[t];
				store[s] = INT_MAX;
			}
        }
        else
        {
			if(--cnt[height[u]] == 0)
				break;
			height[u] = 2 * n;
			cur[u] = head[u];
			for(now = head[u]; now != -1; now = edge[now].next)
			{
				v = edge[now].v;
				if(edge[now].cap > edge[now].flow && height[u] > height[v] + 1)
					height[u] = height[v] + 1;
			}
			cnt[height[u]]++;
			if(u != s)
				u = edge[path[u]].u;
        } 
    }
    return ans; 
} 



 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值