UVA1324 拆点 小心坑!

本文介绍了一种基于最大流算法解决特定问题的实现方法,通过不断枚举和添加边来寻找满足条件的最大流,最终输出解决方案。文章详细展示了算法的具体步骤,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述不多说 思路把一个点拆成T个 不断枚举T并往图上连边加点 知道最大流等于k 最后打印方案 因为原弧和其反向弧总是在一起 所以可以直接枚举检验时候有流量 

处理 a->b b->a的方法 显然这两条边是续加入的 可快速找到对应的边 统计流量 如果同时有流量则不移动

特别注意!!! s进行最大流算法是要在刚好满足的时刻退出 不然会导致不存在的流量出现


#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define MAXN 6000
#define MAXM 3000000
#define MAXK 500
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int, int> pii;
pii A[200+10];
int Move[MAXK+10], pos[MAXK+10];
int n, m, S, T, k;
template <int maxn, int maxm>
struct Isap
{
    int ecnt;
    int d[maxn+10], pre[maxn+10], cur[maxn+10], gap[maxn+10];
    int adj[maxn+10];
    struct node {
        int v, next, c, f;
    }Edge[maxm*2+10];
    void init() { memset(adj, -1, sizeof(adj)); ecnt = 0; }
    void addedge(int u, int v, int c)
    {
        Edge[ecnt].v = v;
        Edge[ecnt].c = c;
        Edge[ecnt].f = 0;
        Edge[ecnt].next = adj[u];
        adj[u] = ecnt++;
    }
    void add(int u, int v, int c)
    {
        addedge(u, v, c);
        addedge(v, u, 0);
    }
    void init_dis(int t) // 据说单次意义不大的优化 多次小规模才会出现差距 仅仅是据说
    {
        queue <int> q;
        memset(d, -1, sizeof(d));
        memset(gap, 0, sizeof(gap));
        d[t] = 0;
        q.push(t);
        while(!q.empty())
        {
            int u = q.front(); q.pop();
            gap[d[u]]++;
            for(int i = adj[u]; ~i; i = Edge[i].next) 
            {
                int v = Edge[i].v;
                if(d[v] == -1) { d[v] = d[u] + 1; q.push(v); }
            }
        }
    }
    int ISAP(int s, int t, int num, int limit)
    {
        init_dis(t);
        int ans = 0, u = s;
        int Flow = INF;
        memcpy(cur, adj, sizeof(adj));
        while(d[s] < num)
        {
            int &i = cur[u];
            for(; ~i; i = Edge[i].next)
            {
                int v = Edge[i].v;
                if(Edge[i].c > Edge[i].f && d[u] == d[v] + 1)
                {
                    u = v;
                    pre[v] = i;
                    Flow = min(Flow, Edge[i].c - Edge[i].f);
                    if(u == t)
                    { 
                        while(u != s) {
                            int j = pre[u];
                            Edge[j].f += Flow;
                            Edge[j^1].f -= Flow;
                            u = Edge[j^1].v;
                        }
                        ans += Flow;
                        Flow = INF;
                    }
					if(ans == limit) return ans;
                    break;
                }
            }
            if(i == -1)
            {
                if(--gap[d[u]] == 0) break;
                int dmin = num - 1;
                cur[u] = adj[u];
                for(int j = adj[u]; ~j; j = Edge[j].next) if(Edge[j].c > Edge[j].f) dmin = min(dmin, d[Edge[j].v]);
                d[u] = dmin+1;
                gap[d[u]]++;
                if(u != s) u = Edge[pre[u]^1].v;
            }
        }
        return ans;
    }
};  
Isap <MAXN+10, MAXM+10> sap;
vector <pii> step;
void print_ans(int Day)
{
	int id = 0;
	for(int i = 0; i < k; i++) pos[i] = S;
	for(int i = 1; i <= Day; i++)
	{
		id += 2 * n;
		int j = 1;
		step.clear();
		for(int j = 0; j < m; j++)
		{
			int f1 = sap.Edge[id].f; id += 2;
			int f2 = sap.Edge[id].f; id += 2;
			if(f1 && !f2) step.push_back(make_pair(A[j].first % n, A[j].second % n));
			else if(!f1 && f2) step.push_back(make_pair(A[j].second % n, A[j].first % n));
		}
		printf("%d", step.size());
		memset(Move, 0, sizeof(Move));
		for(int j = 0; j < step.size(); j++)
		{
			int u = step[j].first, v = step[j].second;
			for(int p = 0; p < k; p++)
				if(!Move[p] && pos[p] == u)
				{
					Move[p] = 1;
					printf(" %d %d", p+1, v+1);
					pos[p] = v;
					break;
				}
		}
		printf("\n");
	}  
}
int main()
{
	while(scanf("%d%d%d%d%d", &n, &m, &k, &S, &T) == 5)
	{
		S--; T--;
		sap.init();
		int Day = 1, Flow = 0;
		for(int i = 0; i < m; i++) 
		{
			int u, v;
			scanf("%d%d", &u, &v);
			u--; v--;
			A[i] = make_pair(u, v);
		}
		for(;;)
		{
			int Last = (Day-1) * n, Now = Day * n;
			for(int i = 0; i < n; i++)
				sap.add(Last+i, Now+i, INF);
			for(int i = 0; i < m; i++)
			{
				int u = A[i].first, v = A[i].second;
				sap.add(Last+u, Now+v, 1);
				sap.add(Last+v, Now+u, 1);
			}
			Flow += sap.ISAP(S, T + Now, (Day + 1) * n, k - Flow);
			if(Flow >= k) break;
			Day++;
		}
		printf("%d\n", Day);
		print_ans(Day);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值