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(kx1)+bx,kx0

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;
}

  

转载于:https://www.cnblogs.com/zhangchengc919/p/5779429.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值