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 string. And makes this subsequence score maximum. The subsequence’s score is calculated as follows:
Score= Value – Total_Cost
The calculation of the Cost is as follows:
If the number of characters x in the subsequence is kx, And the two coefficients are ax,bx,The cost of character x calculated as follows:

{cost[x]=0,kx=0cost[x]=ax∗(kx−1)+bx,kx≠0

TotalCost=∑i=09cost[i]

The calculation of the Value is as follows:

Value=0;for(int i=1;i<=length(substr);++i){     for(int j=1;j<=length(substr);++j){          if(i!=j)              Value+=w[id[i]][id[j]];     }}

id[i] is the position of the subsequence’s ith character in the original string,for example,if the original string is “13579”,and the subsubquence is “159”,then the array id ={1,3,5}. The w is a weight matrix.

Input

The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains one integers n, the length of a string.
Next line contains the string S.
Next ten lines,each line contains ai,bi,denote the char i’s(0-9) coefficients
Next is a n*n matrix w.
Limits:
T<=20,
0<=n<=100
0<=ai<=bi<=1000
0<=w[i][j]<=50

Output

Each test output one line “Case #x: y” , where x is the case number ,staring from 1. y is the Maximum score.

Sample Input

1

3

135

1 2

1 2

1 2

1 2

1 2

1 2

1 2

1 2

1 2

1 2

0 0 3

1 0 0

4 0 0

Sample Output

Case #1: 3

题意:

求这个式子的最大值;

思路:

这个也是最大权闭合子图的应用,如果要选第i行第j个w[i][j]那么一定要选序列中第i个和第j个,选了第i个和第j个那么一定要选相应的数字了;

题解是这样给的:

第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分)
第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费)
第三类:对于10种字符拆出10个点,每个点的权值为  -(b[x]-a[x])

然后就是建图跑最大流的算法了;

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <bits/stdc++.h>
#include <stack>
#include <map>

using namespace std;

#define For(i,j,n) for(int i=j;i<=n;i++)
#define mst(ss,b) memset(ss,b,sizeof(ss));

typedef  long long LL;

template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<‘0‘||CH>‘9‘;F= CH==‘-‘,CH=getchar());
    for(num=0;CH>=‘0‘&&CH<=‘9‘;num=num*10+CH-‘0‘,CH=getchar());
    F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
    if(!p) { puts("0"); return; }
    while(p) stk[++ tp] = p%10, p/=10;
    while(tp) putchar(stk[tp--] + ‘0‘);
    putchar(‘\n‘);
}

const LL mod=1e9+7;
const double PI=acos(-1.0);
const int inf=1e9;
const int N=1e4+120;
const int maxn=1e4+220;
const double eps=1e-12;

int a[12],b[12],c[110],w[110][110];
char str[110];

struct Edge
{
    int from,to,cap,flow;
};
vector<int>G[maxn];
vector<Edge>edges;
int cur[maxn],d[maxn],s,t,n,m,sum;
bool vis[maxn];

inline void add_edge(int from,int to,int cap)
{
    edges.push_back((Edge){from,to,cap,0});
    edges.push_back((Edge){to,from,0,0});
    m=edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
}

bool bfs()
{
    mst(vis,0);
    queue<int>qu;
    qu.push(s);
    d[s]=0;vis[s]=1;
    while(!qu.empty())
    {
        int fr=qu.front();qu.pop();
        for(int i=0;i<G[fr].size();i++)
        {
            Edge& e=edges[G[fr][i]];
            if(!vis[e.to]&&e.cap>e.flow)
            {
                vis[e.to]=1;
                d[e.to]=d[fr]+1;
                qu.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)))>0)
        {
            e.flow+=f;
            edges[G[x][i]^1].flow-=f;
            flow+=f;
            a-=f;
            if(a==0)break;
        }
    }
    return flow;
}

int Dinic()//跑最大流Dinic算最小割
{
    int flow=0;
    while(bfs())
    {
        mst(cur,0);
        flow+=dfs(s,inf);
    }
    return flow;
}
inline void Init()//建图
{
    sum=0;s=0;
    int tot=n+10;
    For(i,1,n)
    {
        For(j,i+1,n)
        {
            tot++;
            add_edge(tot,i,inf);
            add_edge(tot,j,inf);
            add_edge(s,tot,w[i][j]+w[j][i]);
            sum+=w[i][j]+w[j][i];
        }
    }
    tot++;t=tot;
    For(i,1,n)
    {
        add_edge(i,c[i]+n+1,inf);
        add_edge(i,t,a[c[i]]);
    }
    For(i,0,9)
    {
        add_edge(i+n+1,t,b[i]-a[i]);
    }
}

int main()
{
    int t,Case=0;
    read(t);
    while(t--)
    {
        edges.clear();
        For(i,0,maxn-2)G[i].clear();
        read(n);
        scanf("%s",str);
        For(i,0,n-1)c[i+1]=str[i]-‘0‘;
        For(i,0,9)read(a[i]),read(b[i]);
        For(i,1,n)For(j,1,n)read(w[i][j]);
        Init();
        sum-=Dinic();
        printf("Case #%d: %d\n",++Case,sum);
    }
    return 0;
}

  

时间: 2024-08-28 05:22:18

hdu-5772 String problem(最大权闭合子图)的相关文章

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

hdu 3996 Gold Mine 最大权闭合子图

Gold Mine Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2374    Accepted Submission(s): 514 Problem Description Long long ago, there is a gold mine.The mine consist of many layout, so some are

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,对于第二类中的点

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

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个点,其对应的字

HDU4971 A simple brute force problem.(强连通分量缩点 + 最大权闭合子图)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4971 Description There's a company with several projects to be done. Finish a project will get you profits. However, there are some technical problems for some specific projects. To solve the proble

HDU 3879 Base Station(最大权闭合子图)

经典例题,好像说可以转化成maxflow(n,n+m),暂时只可以勉强理解maxflow(n+m,n+m)的做法. 题意:输入n个点,m条边的无向图.点权为负,边权为正,输出最大权闭合子图的权值. (最大权闭合子图:图中各点的后继必然也在图中) 构图攻略:将边看做点(有的题边是没有权的,建模稍微有点不同), 对原本的边e[i](u,v,w)连3条边(S,n+i,w),(n+i,u,inf),(n+i,v,inf). 对原本的点v,连1条边(v,T,p[v]). 即正权点与源点连,负权点与汇点连.

HDU 5855 Less Time, More profit(最大权闭合子图)

题目链接:点击打开链接 思路: 最大权闭合子图的裸题,  给个学习资料:点击打开链接 当结点即有正权值又有负数权值时, 怎么求任意闭合子图的最大和呢?  只要求出最小割E, 用总的正数权值TOT 减去E就是答案. 细节参见代码: #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector&

[最大权闭合子图小练]

[POJ 2987]每个人都为公司带来一个收益,公司老板要裁员(当然是业绩不好给公司带来负收益的人被裁掉啦~),然而踢走一个人会把他的下属都踢走,求最大收益 最大权闭合子图~,其实就是最小割啦,此题要求最小化走的人数,然而就是最小割中的人数QAQ(并不知道为什么),dfs(S)相关的点 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include