zoukankan      html  css  js  c++  java
  • Oooooooo AAAAE

    题面:

    这个游戏可以简化成:谱面由N个键和M条连线组成,每两个键之间有一个连线,玩家需要在键之间滑动,且连线的方向是固定的,玩家每次选择一个键,把所有从这个键出发的连线都消除掉,花费为ai,也可以将每个结束在这个点的连线消除,花费Bi。不用担心,LiMn2O4的手指足够多。最后让连线全部消失,得分就是总花费。花费越少,分数越高。求出最小花费。

    思路:

    1.最小点权覆盖集:从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。最大点权独立集:在二分图中找到权值和最大的点集,使得它们之间两两没有边。
    2.借鉴了题解的思路。才知道是网络流最小点权覆盖问题。设立源点s和t,s连边到点i,容量为i点的权值;点j连边到t,容量为j点权值;原二分图中的边容量为INF,求最大流即为最小点权覆盖。
    3.扩展:最大点权独立集可转化为最小点权覆盖问题,

    最大点权独立集 = 总权值 - 最小点权覆盖集

    经典的网络流最小点权覆盖问题,首先拆点,分成左右两部分,源点向所有左节点连一条边,流量为删除出边的花费。所有右节点向汇点连一条边,流量为删除入边的费用。对于每条输入给定的边<u,v>,其在左边的点为u,v,右边的点为u’,v’,那么我们连一条<u,v’>的边,流量为∞(正无穷才不会对可行流上最小的容量产生限制)。跑一边最大流,得到的答案就是最小的费用。
    首先,如果没有花费的话,这道题就是简单的最小点覆盖集。加上了点权之后,我们就要将最小割的思想融合进去。要注意费用,一定要符合S->T的顺序

    代码:

      1 #include<bits/stdc++.h>
      2 const int inf = 0x3f3f3f3f;
      3 using namespace std;
      4  
      5 int n, m, t, h[250];
      6 int a[110], b[110];
      7 int d[250];
      8 queue<int>q;
      9  
     10 struct node
     11 {
     12     int t,n,w; 
     13 }E[20000];
     14  
     15 void add(int u, int v, int w)
     16 {
     17     E[t].t=v;
     18     E[t].w=w;
     19     E[t].n = h[u];
     20     h[u] =t++;
     21 }
     22  
     23 int bfs(int s, int t) 
     24 {
     25     if(s== t)
     26         return 0;
     27     while(q.size())
     28         q.pop();
     29     memset(d,-1,sizeof(d));
     30     d[s] = 1;
     31     q.push(s);
     32     while(q.size())
     33     {
     34         int k = q.front();
     35         q.pop();
     36         for(int i = h[k]; i != -1; i = E[i].n)
     37         {
     38             int to = E[i].t;
     39             if(d[to] == -1 && E[i].w > 0)
     40             {
     41                 d[to] = d[k] + 1;
     42                 q.push(to);
     43             }
     44         }
     45     }
     46     return d[t] != -1;
     47 }
     48 int dfs(int x, int t, int cnt)
     49 {
     50     if(x==t)
     51         return cnt;
     52     for(int i = h[x]; i != -1; i = E[i].n)
     53     {
     54         int to = E[i].t;
     55         if(d[to] == d[x] + 1 && E[i].w > 0)
     56         {
     57             int f = dfs(to, t, min(E[i].w, cnt));
     58             if(f> 0)
     59             {
     60                 E[i].w -= f;
     61                 E[i^1].w += f;
     62                 return f;
     63             }
     64         }
     65     }
     66     return -1;
     67 }
     68  
     69 void dinic(int s, int t)
     70 {
     71     long long ans = 0;
     72     while(bfs(s, t))
     73     {
     74         while(1)
     75         {
     76             int k= dfs(s, t, inf);
     77             if(k == -1)
     78                 break;
     79             ans += k;
     80         }
     81     }
     82     printf("%lld
    ", ans);
     83 }
     84  
     85 int main()
     86 {
     87     memset(h,-1,sizeof(h));
     88     scanf("%d%d", &n, &m); 
     89     for(int i = 1; i <= n; i ++) 
     90     {
     91         scanf("%d", &a[i]);
     92         add(i + n, 2 * n + 1, a[i]);
     93         add(2 * n + 1, i + n, 0);
     94     }
     95     for(int i = 1; i <= n; i ++)
     96     {
     97         scanf("%d", &b[i]);
     98         add(0, i, b[i]);
     99         add(i, 0, 0);
    100     }
    101     for(int i = 1; i <= m; i ++)
    102     {
    103         int a, b;
    104         scanf("%d%d", &a, &b);
    105         add(a, b + n, inf);
    106         add(b + n, a, 0);
    107     }
    108     dinic(0, 2 * n + 1);
    109 }
    View Code
  • 相关阅读:
    平方分割poj2104K-th Number
    平方分割poj2104K-th Number
    GIT学习之路第五天 分支管理
    GIT学习之路第五天 分支管理
    daily_journal_2 神奇的一天
    daily_journal_2 神奇的一天
    51nod1264 线段相交
    51nod1264 线段相交
    51nod1265判断四点共面
    51nod1265判断四点共面
  • 原文地址:https://www.cnblogs.com/Accpted/p/11185556.html
Copyright © 2011-2022 走看看