zoukankan      html  css  js  c++  java
  • 【POJ3422】Kaka's Matrix Travels【费用流】

    题目大意:

    题目链接:http://poj.org/problem?id=3422
    kk次传纸条。
    传纸条问题都不知道的话那我也就没办法了。
    真香


    思路:

    kk次传纸条也是一个比较经典的题目。它的解法是费用流。
    如果重复经过的格子是重复计分的,那么就是一个很裸的费用流了(其实答案就是一次传纸条×k imes k),着重思考如何处理“重复的格子不重复计分”。
    那么显然是需要拆点的。把每一个点aa拆成a1a_1a2a_2,分别表示入点和出点。
    考虑如何在这两个点之间连边。显然,这两个点中间一共要连kk条边,因为最多会经过kk次。但是只有其中1条边是有费用的,其他k1k-1条边都是没有费用的。
    那么显然要在a1,a2a_1,a_2之间连两种边:

    • 一条流量为1,费用为这个格子的权值的边
    • 一条流量为k1k-1费用为0的边

    这样就可以有效解决重复的格子不重复计分的问题了。
    接下来的连边就非常显然了。

    • S11S o1_1(点1的入点),流量mm,费用0
    • n22T{n^2}_2 o T(最后一个点的出点,总共有n2n^2个点),流量mm,费用0
    • i2(i+n)1i_2 o (i+n)_1,流量mm,费用0
    • i2(i+1)1i_2 o (i+1)_1,流量mm,费用0

    跑最大费用最大流就可以了。


    代码:

    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    
    const int N=5010,M=200010;
    int n,m,x,S,T,tot=1,head[N],dis[N],pre[N];
    bool vis[N];
    
    struct edge
    {
    	int next,to,flow,cost,from;
    }e[M];
    
    void add(int from,int to,int flow,int cost)
    {
    	e[++tot].to=to;
    	e[tot].from=from;
    	e[tot].flow=flow;
    	e[tot].cost=cost;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    bool spfa()  //费用流模板(spfa,addflow,mcmf)
    {
    	memset(dis,0xcf,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	memset(pre,0,sizeof(pre));
    	dis[S]=0,vis[S]=1;
    	queue<int> q;
    	q.push(S);
    	while (q.size())
    	{
    		int u=q.front(),v;
    		q.pop();
    		vis[u]=0;
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			v=e[i].to;
    			if (e[i].flow&&dis[v]<dis[u]+e[i].cost)
    			{
    				dis[v]=dis[u]+e[i].cost;
    				pre[v]=i;
    				if (!vis[v])
    				{
    					vis[v]=1;
    					q.push(v);
    				}
    			}
    		}
    	}
    	return dis[T]>0;
    }
    
    int addflow()
    {
    	int minflow=0x3f3f3f3f;
    	for (int i=T;i!=S;i=e[pre[i]].from)
    		minflow=min(minflow,e[pre[i]].flow);
    	for (int i=T;i!=S;i=e[pre[i]].from)
    	{
    		e[pre[i]].flow-=minflow;
    		e[pre[i]^1].flow+=minflow;
    	}
    	return minflow*dis[T];
    }
    
    int mcmf()
    {
    	int cost=0;
    	while (spfa())
    		cost+=addflow();
    	return cost;
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n*n;i++)
    	{
    		scanf("%d",&x);
    		add(i,i+n*n,1,x);
    		add(i+n*n,i,0,-x);
    		add(i,i+n*n,m-1,0);
    		add(i+n*n,i,0,0);
    		if (i+n<=n*n)
    		{
    			add(i+n*n,i+n,m,0);
    			add(i+n,i+n*n,0,0);
    		}
    		if (i%n)
    		{
    			add(i+n*n,i+1,m,0);
    			add(i+1,i+n*n,0,0);
    		}
    	}
    	S=n*n*2+1;
    	T=n*n*2+2;
    	add(S,1,m,0);
    	add(1,S,0,0);
    	add(n*n*2,T,m,0);
    	add(T,n*n*2,0,0);
    	printf("%d",mcmf());
    	return 0;
    }
    
  • 相关阅读:
    SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSAS 系列
    微软BI 之SSRS 系列
    微软BI 之SSRS 系列
    配置 SQL Server Email 发送以及 Job 的 Notification通知功能
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998255.html
Copyright © 2011-2022 走看看