• 【网络流#8】POJ 3469 Dual Core CPU 最小割【ISAP模板】


    【题意】有n个程序,分别在两个内核中运行,程序i在内核A上运行代价为ai,在内核B上运行的代价为bi,现在有程序间数据交换,如果两个程序在同一核上运行,则不产生额外代价,在不同核上运行则产生Cij的额外代价,问如何划分使得代价最小。


    用最小的费用将对象划分为两个集合的问题,常常可以转换为最小割后顺利解决

    建立源点与汇点,每个程序视为一个点,源点与在各个程序连一条边,最大流量为bi,汇点与各个程序连一条边,最大流量ai,对于有额外代价的程序,连一条双向边,流量为cij。

    一开始用Dinic算法做,结果TLE,在POJ的discuss里看到了这篇http://www.cnblogs.com/zhsl/archive/2012/12/03/2800092.html

    ISAP的效率要优于DINIC所以这道题需要使用ISAP。

    ISAP的模板的话找到了这篇http://kenby.iteye.com/blog/945454相当不错所以借鉴了过来。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<string>
    #include<sstream>
    #define eps 1e-9
    #define ALL(x) x.begin(),x.end()
    #define INS(x) inserter(x,x.begin())
    #define FOR(i,j,k) for(int i=j;i<=k;i++)
    #define MAXN 20010
    #define MAXM 1800000
    #define INF 0x3fffffff
    using namespace std;
    typedef long long LL;
    int i,j,k,n,m,x,y,T,ans,big,cas,w;
    bool flag;
    
    struct Edge{
    	int u,v,weight;
    	int next;
    }edge[MAXM];
    int head[MAXN];	/* head[u]表示顶点u第一条邻接边的序号, 若head[u] = -1, u没有邻接边 */
    int	current;	/* 当前有多少条边 */
    
    void add_edge(int u, int v, int weight) 
    {
    	/* 添加正向边u->v */
    	edge[current].u = u;
    	edge[current].v = v;
    	edge[current].weight = weight;
    	edge[current].next = head[u];
    	head[u] = current++;
    	/* 添加反向边v->u */
    	edge[current].u = v;
    	edge[current].v = u;
    	edge[current].weight = 0;
    	edge[current].next = head[v];
    	head[v] = current++;
    }
    
    int isap(int s, int e) 
    {
    	int	i,u,v,max_flow,aug,min_lev;
    
    	/* 寻找增广路径的过程中, curedge[u]保存的是对于顶点u当前遍历的边, 寻找顶点u的邻接边时不用每次
    	 * 都从head[u]开始找, 而是从curedge[u]开始找, 这样就减少了搜索次数
    	 * 当增广路径找到后
    	 * curedge保存的就是一条增广路径了, 比如
    	 * 0---四-->1---六-->2--七--->3---八--->4 0,1,2,3,4是顶点号, 四六七八是边的序号
    	 * curedge[0] = 四, curedge[1] = 六, ... curedge[3] = 8, curedge[i]即保存找过的轨迹 
    	 */
    	int	curedge[MAXN],parent[MAXN],level[MAXN];
    
    	/* count[l]表示对于属于层次l的顶点个数, 如果某个层次没有顶点了, 
    	 * 就出现断层, 意味着没有增广路径了, 这就是gap优化, 可以提前结束寻找过程 
    	 * augment[v]表示从源点到顶点v中允许的最大流量, 即这条路线的最小权重
    	 */
    	int count[MAXN],augment[MAXN];
    
    	memset(level,0,sizeof(level));
    	memset(count,0,sizeof(count));
    	//初始时每个顶点都从第一条边开始找
    	for (i=0;i<=n;i++)
    	{
    		curedge[i] = head[i];
    	}
    	max_flow=0;
    	augment[s]=INF;
    	parent[s]=-1;
    	u=s;
    
    	while (level[s]<n)	/* 不能写成level[s] < MAX_INT */
    	{
    		if (u==e)		/* 找到一条增广路径 */
    		{
    			max_flow+=augment[e];
    			aug=augment[e];
    			//debug("找到一条增广路径, augment = %d
    ", aug);
    			//debug("%d", e);
    			for (v=parent[e];v!=-1;v=parent[v])	/* 从后往前遍历路径 */
    			{
    				i=curedge[v];
    				//debug("<--%d", v);
    				edge[i].weight-=aug;
    				edge[i^1].weight+=aug;	/* 如果i是偶数, i^1 = i+1, 如果i是奇数, i^1 = i-1 */
    				augment[edge[i].v]-=aug;
    				if (edge[i].weight==0) u=v;	/* u指向增广后最后可达的顶点, 下次就从它继续找 */
    			}
    			//debug("
    ");
    		}
    		/* 从顶点u往下找邻接点 */
    		for (i=curedge[u];i!=-1;i=edge[i].next)	/* 从curedge[u]开始找, 而不是head[u]从头开始, curedge[u]保存的是上次找过的边 */
    		{
    			v=edge[i].v;
    			if (edge[i].weight>0 && level[u]==(level[v]+1))	/* 找到一条边就停止 */
    			{
    				augment[v]=min(augment[u],edge[i].weight);
    				curedge[u]=i;
    				parent[v]=u;
    				u=v;
    				break;
    			}
    		}
    		if (i==-1) 	/* 没有邻接点, 回溯到上一个点 */
    		{
    			if (--count[level[u]]==0) 
    			{
    				//debug("顶点%d在level %d断层
    ", u, level[u]);//GAP优化 
    				break;
    			}
    			curedge[u]=head[u];	/* 顶点u的所有边都试过了,没有出路, 更新了u的level后, 又从第一条边开始找 */
    			//找出level最小的邻接点
    			min_lev=n;
    			for (i=head[u];i!=-1;i=edge[i].next) 
    			{
    				if (edge[i].weight>0) 
    				{
    					min_lev=min(level[edge[i].v],min_lev);
    				}
    			}
    			level[u]=min_lev+1;
    			count[level[u]]++;
    			//debug("顶点%d的level= %d
    ", u, level[u]);
    			//debug("顶点%d走不通, 回到%d
    ", u, edge[curedge[u]].u);
    			if (u!=s) u=parent[u];	/* 回退到上一个顶点 */
    		}
    	}
    	return max_flow;
    }
    
    int main()
    {
        int m,u,v,w,a,b;
        while (scanf("%d %d",&n,&m)!=EOF)
        {
            memset(edge,0,sizeof(edge));
            memset(head,-1,sizeof(head));
            current=0;
            for (u=1;u<=n;u++)
            {
                scanf("%d %d",&a,&b);
                add_edge(0,u,a);
                add_edge(u,n+1,b);
            }
            while (m--)
            {
                scanf("%d %d %d",&u,&v,&w);
                /* 如果调用函数添加边, 速度明显边慢 */
                //add_edge(u, v, w);
                //add_edge(v, u, w);
     
                /* 添加正向边u->v */
                edge[current].u = u;
                edge[current].v = v;
                edge[current].weight = w;
                edge[current].next = head[u];
                head[u] = current++;
                /* 添加反向边v->u */
                edge[current].u = v;
                edge[current].v = u;
                edge[current].weight = w;
                edge[current].next = head[v];
                head[v] = current++;
            }
            n+=2;
            printf("%d
    ",isap(0,n-1));
        }
        return 0;
    }
    

      

  • 相关阅读:
    [C#菜鸟]C# Hook (三) Windows常用消息大全
    [C#菜鸟]C# Hook (二) 常用钩子的类型
    C# hook WndProc
    Win7、win8、win10下实现精准截获Explorer拷贝行为
    对“XXX::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们
    VC中MessageBox与AfxMessageBox用法与区别
    C# 强命名程序集,防止dll被修改,混淆下发布
    easyhook报错The given 64-Bit library does not exist
    easyhook源码分析三——申请钩子
    Ext3日记文件系统为什么文件系统还会损坏?
  • 原文地址:https://www.cnblogs.com/zhyfzy/p/4130421.html
Copyright © 2020-2023  润新知