zoukankan      html  css  js  c++  java
  • P2469 [SDOI2010]星际竞速

    pro:
    https://www.luogu.com.cn/problem/P2469

    sol:
    发现这个模型和最小路径覆盖有着密切的联系

    考虑最小路径覆盖是怎么实现的

    一开始用n条长度为1的路径去覆盖n个点

    使初始答案为n

    每个点拆成入点和出点

    对于原图每条边x--->y

    然后x的出点和y的入点连边

    跑二分图匹配

    求最大流flow

    则ans=n-flow

    因为每匹配两条边就等价于把x所在的路径和y所在路径连接在一起

    答案应该-1

    再考虑本题

    还是先考虑n条路径的情况

    答案显然为(sum_{i=1}^n a_i)

    然后考虑连接两条路径时能省掉多少代价

    发现新增了边权(w),减少了新开一条路径的费用(a_y)

    因此这个问题和最小路径类似

    只不过不在是简单的二分图最大匹配

    而是变成了一个带权二分图最大匹配

    这个玩意显然就是个最大费用流

    冲就完事了

    #include<bits/stdc++.h>
    #define N 11000
    #define M 110000
    #define eps 1e-7
    #define inf 1e12
    #define db double
    #define ll long long
    #define ldb long double
    #define ull unsigned long long
    using namespace std;
    inline ll read()
    {
    	char ch=0;
    	ll x=0,flag=1;
    	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
    	return x*flag;
    }
    struct edge
    {
    	ll to,nxt,flow,w;
    }e[M];
    ll num,head[N];
    inline void add(ll x,ll y,ll w,ll z)
    {
    	e[++num]=(edge){y,head[x],w,+z};head[x]=num;
    	e[++num]=(edge){x,head[y],0,-z};head[y]=num; 
    }
    bool in_queue[N];
    ll n,m,s,t,dis[N],pre[N],last[N],flow[N];
    queue<ll>q;			
    bool spfa()
    {
    	for(ll i=0;i<=t;i++)dis[i]=-inf,flow[i]=+inf;
    	dis[s]=0;q.push(s);in_queue[s]=true;
    	while(!q.empty())
    	{
    		ll x=q.front();q.pop();in_queue[x]=false;
    		for(ll i=head[x];i!=-1;i=e[i].nxt)
    		{
    			ll to=e[i].to;
    			if(e[i].flow&&dis[to]<dis[x]+e[i].w)
    			{
    				pre[to]=x;last[to]=i;
    				dis[to]=dis[x]+e[i].w;
    				flow[to]=min(flow[x],e[i].flow);
    				if(!in_queue[to])q.push(to),in_queue[to]=true;
    			}
    		}
    	}
    	return dis[t]>0;
    }
    void dfs(ll x)
    {
    	if(x==s)return;
    	ll i=last[x];
    	e[i].flow-=flow[t];
    	e[i^1].flow+=flow[t];
    	dfs(pre[x]);
    }
    ll a[N];
    int main()
    {
    	n=read();m=read();s=2*n+1;t=2*n+2;
    	num=-1;memset(head,-1,sizeof(head));
    	ll ans=0;
    	add(s,t,+inf,0); 
    	for(ll i=1;i<=n;i++)
    	{
    		a[i]=read();
    		add(s,i,1,0);
    		add(i+n,t,1,0);
    		ans+=a[i];
    	}
    	for(ll i=1;i<=m;i++)
    	{
    		ll x=read(),y=read(),z=read();
    		if(x>y)swap(x,y);
    		if(a[y]-z>0)add(x,y+n,1,a[y]-z);
    	}
    	while(spfa())ans-=dis[t]*flow[t],dfs(t);
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    彻底搞清分库分表(垂直分库,垂直分表,水平分库,水平分表)
    linux服务器上tcp有大量time_wait状态的解决方法和原因解释
    mysql,既可以自己的字段相乘,也可以乘固定的字段
    vscode 滚动设置字体大小
    nodejs 定时任务 node-schedule 库
    Node.js中的环境变量
    js 打印错误堆栈
    springboot 返回的json中忽略null属性值,不传递
    idea跳转到指定行列快捷键
    Spring boot + MyBatis返回map中null值处理
  • 原文地址:https://www.cnblogs.com/Creed-qwq/p/13774275.html
Copyright © 2011-2022 走看看