HDU5772 String problem 最大权闭合图+巧妙建图

题意:自己看吧(不是很好说)

分析:

网络流:最大权闭合子图。

思路如下:

首先将点分为3类

第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分)

第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费)

第三类:对于10种字符拆出10个点,每个点的权值为  -(b[x]-a[x])

那么我们可以得到一个关系图 ,对于第一类中的点Pij,如果想要选择Pij,你就必须要选中第二类中的点i和j,对于第二类中的点如果你想选中第i个点,其对应的字符s[i],那么就必须选中第三类中s[i] 对应的点,因为每个种类的点第一次选中时花费是b[s[i]],而第二类中花费都是a[s[i]],一定要补上b[s[i]]-a[s[i]],而且只需要补上一次。

得到上面的关系图后然后就是普通的最大权闭合子图问题,直接求解即可。

注:吐槽,我想说真的是神思路,加网络流大法好,我只想说没有刷过网络流24题的人伤不起啊

首先想会做这个题,必须会最大权闭合子图的概念,这个是网络流24题之一(多刷题就是好),但是就算是会了这个建图,也不一定会做这个题

虽然说这个题看数据范围什么的,限制条件这么多的,差不多能想到是网络流,但是伤在不会建图啊

这个题很巧妙的点,就是一个子序列的贡献是每两个不同点组成的,这是独立的,只和这两个元素有关,和序列的其它元素无关,这样每两个元素就可以虚拟一个点了

然后按照题解建成有向图,对于u-->v,选u必须选v 对于这种图的求最大方案,显然就是求最大权闭合图

如何建图,请见http://www.cnblogs.com/kane0526/archive/2013/04/05/3001557.html(可以顺便把这个题做一下,是个裸题)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef  long long LL;
const int INF = 0x3f3f3f3f;
const int maxn=4e4+5;
struct Edge
{
    int from,to,cap,flow;
    Edge(int u,int v,int c,int d):from(u),to(v),cap(c),flow(d) {}
};
struct dinic
{
    int s,t;
    vector<Edge>edges;
    vector<int>G[maxn];
    int d[maxn];
    int cur[maxn];
    bool vis[maxn];
    void init(){
      for(int i=0;i<maxn;++i)G[i].clear();
      edges.clear();
    }
    bool bfs()
    {
        memset(vis,0,sizeof(vis));
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            for(int i=0; i<G[x].size(); i++)
            {
                Edge &e= edges[G[x][i]];
                if(!vis[e.to]&&e.cap>e.flow)
                {
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int dfs(int x,int a)
    {
        if(x==t||a==0)return a;
        int flow=0,f;
        for(int &i=cur[x]; i<G[x].size(); i++)
        {
            Edge &e=edges[G[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow))))
            {
                e.flow+=f;
                edges[G[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    LL maxflow(int s,int t)
    {
        this->s=s;
        this->t=t;
        LL flow=0;
        while(bfs())
        {
            memset(cur,0,sizeof(cur));
            flow+=dfs(s,INF);
        }
        return flow;
    }
    void addedge(int u,int v,int c)
    {
        Edge x(u,v,c,0),y(v,u,0,0);
        edges.push_back(x);
        edges.push_back(y);
        int l=edges.size();
        G[u].push_back(l-2);
        G[v].push_back(l-1);
    }
}solve;
int a[11],b[11],T,n,w[102][102],kase;
char s[105];
int main(){
  scanf("%d",&T);
  while(T--){
     solve.init();
     scanf("%d%s",&n,s+1);
     for(int i=1;i<=10;++i)
        scanf("%d%d",&a[i],&b[i]);
     for(int i=1;i<=n;++i)
      for(int j=1;j<=n;++j)
        scanf("%d",&w[i][j]);
     int cnt=0,p=n*(n-1)/2;
     LL sum=0;
     for(int i=1;i<n;++i){
       for(int j=i+1;j<=n;++j){
         ++cnt;
         if(w[i][j]+w[j][i]>0){
          solve.addedge(0,cnt,w[i][j]+w[j][i]);
          sum+=w[i][j]+w[j][i];
         }
         solve.addedge(cnt,p+i,INF);
         solve.addedge(cnt,p+j,INF);
       }
     }
     int t=cnt+n+11;
     for(int i=1;i<=n;++i){
      if(a[s[i]-‘0‘+1]>0)
       solve.addedge(cnt+i,t,a[s[i]-‘0‘+1]);
       solve.addedge(cnt+i,cnt+n+s[i]-‘0‘+1,INF);
     }
     for(int i=cnt+n+1;i<=cnt+n+10;++i)
        if(b[i-cnt-n]-a[i-cnt-n]>0)
      solve.addedge(i,t,b[i-cnt-n]-a[i-cnt-n]);
     printf("Case #%d: %I64d\n",++kase,sum-solve.maxflow(0,t));
  }
  return 0;
}

时间: 2024-08-01 22:34:01

HDU5772 String problem 最大权闭合图+巧妙建图的相关文章

hdu-5772 String problem(最大权闭合子图)

题目链接: String problem Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Problem Description This is a simple problem about string. Now a string S contains only ‘0’-‘9’. ?? wants to select a subsequence from this stri

hdu 5772 String problem(最大权闭合图)

题目链接:hdu 5772 String problem 题意: 给你一个字符串,只含有数字. 你需要选择出一个子序列,使得这个子序列的权值最大. 这个子序列如果这个数字第一次出现就ans-=bx,否则就-=ax 然后如果第i个字符和第j个字符都在子序列里面,那么ans+=w[i][j] 问你最大ans是多少 官方题解: 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace

HDU5772 String problem(最大权闭合子图)

题目..说了很多东西 官方题解是这么说的: 首先将点分为3类 第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分) 第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费) 第三类:对于10种字符拆出10个点,每个点的权值为  -(b[x]-a[x]) 那么我们可以得到一个关系图 ,对于第一类中的点Pij,如果想要选择Pij,你就必须要选中第二类中的点i和j,对于第二类中的点如果你想选中第i个点,其对应的字

HDU 4971 A simple brute force problem. 最大权闭合图

点击打开链接 A simple brute force problem. Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 157    Accepted Submission(s): 99 Problem Description There's a company with several projects to be done. Fi

【算法系列学习】巧妙建图,暴搜去重 Counting Cliques

E - Counting Cliques http://blog.csdn.net/eventqueue/article/details/52973747 http://blog.csdn.net/yuanjunlai141/article/details/52972715 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<

River Problem (hdu 3947 流量等式建图 难题 最小费用最大流)

River Problem Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 515    Accepted Submission(s): 209 Problem Description The River of Bitland is now heavily polluted. To solve this problem, the Kin

BZOJ_4873_[Shoi2017]寿司餐厅_最大权闭合子图

题意:http://www.lydsy.com/JudgeOnline/problem.php?id=4873 分析:我们发现分数正负都有,并且之间有依赖关系,很容易想到最大权闭合子图. 建图: 1.S向正点连边,负点向T连边. 2.选了[i~j]显然要选[i+1~j]和[i~j-1],分别连边. 3.对于i==j的点,向对应的寿司连边. 4.总花费m*x*x+c*x拆成两部分.对于每个代号x,向T连容量为m*x*x的边,c*x这部分我们考虑算f[i][i]时把f[i][i]的值减掉x,当然也可

HDU 5772 String problem

最大权闭合子图.建图巧妙. 最大权闭合子图: #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include

BZOJ 4873 [Shoi2017]寿司餐厅 | 网络流 最大权闭合子图

链接 BZOJ 4873 题解 当年的省选题--还记得蒟蒻的我Day1 20分滚粗-- 这道题是个最大权闭合子图的套路题.严重怀疑出题人就是先画好了图然后照着图编了个3000字的题面.和我喜欢的妹子当年给别人写的情书一样长-- 最大权闭合子图 最大权闭合子图问题:一个有向图中,每个点带有一个权值(有正有负),有向边\(u \to v\)表示选\(u\)必须选\(v\),选出一些点使权值和最大,问权值和最大是多少. 最大权闭合子图的解法:网络流建图,对于每个点\(u\),设权值为\(w_u\),如