zoukankan      html  css  js  c++  java
  • [dfs][dp] Jzoj P4406 拔河

    Description

    有 2n 个人玩拔河,拔河的绳子由左右两段组成,每段绳子上有 n 个位置,第 i 个人可以在左边绳子的 li 位置处,也可以在右边绳子的 ri 位置处。每个位置上有且仅有一个人。每个人有一个实力值 si ,问对于每一种合法方案两边实力值和之差的绝对值最小是多少,如果无解输出 -1 。
     

    Input

    第1行一个整数 n。
    第2 ~ 2n+1行,每行三个整数li, ri, si

    Output

    一个整数表示所求的答案
     

    Sample Input

    6
    1 4 12
    6 1 3
    2 4 5
    3 1 13
    2 6 15
    4 2 8
    5 6 9
    5 2 14
    3 3 5
    6 5 10
    4 5 15
    1 3 13

    Sample Output

    6
     

    Data Constraint

    30%:1 <= n <= 10
    70%:1 <= n <= 103
    100%:1 <= n <= 3 * 104, 1 <= si <= 15

    题解

    • 我们可以将l[i]和r[i]+n连一条边,然后我们发现这就是一个二分图
    • 然后因为每个点都要有一个人,如果一个点度数为0,那么显然要输出-1
    • 如果度数只有1的话,这个点是绝对确定的
    • 那么对于剩下的点,度数都为2,会形成若干偶环
    • 对于每一个偶环,只会有两个种取值方式,顺着走或逆着走,就会产生两个权值,a和b
    • 然后,可以把|a-b|当成一个物品来做背包问题,直接背包,时间复杂度就是O(n*∑si),显然过不了
    • 考虑如何优化,可以把背包改成多重背包

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 using namespace std;
     5 struct edge { int x,y,from,v; }e[60010*2];
     6 int tot,n,boo,to,mx,sum1,sum2,ans,cnt=1,f[60010*15],visit[60010],head[60010],sum[60010],k[60010*15];
     7 void insert(int x,int y,int v) { e[++cnt].y=y; e[cnt].x=x; e[cnt].from=head[x]; head[x]=cnt; e[cnt].v=v; }
     8 void dfs(int x,int k)
     9 {
    10     visit[x]=1;
    11     for (int i=head[x];i;i=e[i].from)
    12         if ((i^1)!=k)
    13             if (!visit[e[i].y]) sum[e[i].y]=sum[x]+e[i].v,mx+=e[i].v,dfs(e[i].y,i);
    14             else 
    15                 if (i/2!=to/2)
    16                 {
    17                     if (boo) { printf("-1"),exit(0); }
    18                     boo=1,to=i;
    19                 }
    20 }
    21 int main()
    22 {
    23     scanf("%d",&n);
    24     for (int i=1;i<=2*n;i++)
    25     {
    26         int l,r,s;
    27         scanf("%d%d%d",&l,&r,&s);
    28         insert(l,r+n,-s),insert(r+n,l,s);
    29     }
    30     for (int i=1;i<=2*n;i++)
    31         if (!visit[i])
    32         {
    33             boo=mx=to=0;
    34             dfs(i,0);
    35             int a=mx-2*sum[e[to].x]-e[to].v,b=mx-2*sum[e[to].y]+e[to].v;
    36             if (a>b) swap(a,b);
    37             k[b-=a]++,sum1+=a,sum2+=b;
    38             
    39         }
    40     f[0]=1,ans=abs(sum1);
    41     for (int i=1;i<=sum2;i++)
    42         if (k[i])
    43             for (int j=sum2;j>=0;j--)
    44                 if (f[j])
    45                     for (int z=1;z<=k[i]&&!f[i*z+j];z++) f[i*z+j]=1;
    46     for (int i=1;i<=sum2;i++) if (f[i]) ans=min(ans,abs(sum1+i));
    47     printf("%d",ans);
    48     return 0;
    49 }
  • 相关阅读:
    事务 TRANSACTION
    SQLServer 数据库镜像+复制切换方案
    微软 codeplex 团队
    codeplex http://metrotoolkit.codeplex.com/
    CodeFlex AutoUpdate
    微软学习网站
    C# 关闭窗体立即停止进程
    反射方法关闭窗体报错的解决方法
    params修饰符
    c# 条形码(求指教)
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9511818.html
Copyright © 2011-2022 走看看