您的位置:首页 > 其它

【HDOJ 】 String problem(最大权闭合图)

2016-07-29 15:27 399 查看
【HDOJ 】 String problem(最大权闭合图)

String problem

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 134 Accepted Submission(s): 61

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=∑9i=0cost[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

Hint

we can choose “15”,id[]={1,3} then Value=w[1][3]+w[3][1]=7,

Total_Cost=2+2=4,Score=7-4=3

Author

FZU

Source

2016 Multi-University Training Contest 4

题目大意:

给出一个由0~9组成的长为n的字符串。

之后10个a,b。

a[i]表示i的花费(0 <= i <= 9)

b[i]表示i的初次花费(0 <= i <= 9)

之后一个n*n的矩阵,表示Pij价值

题目要求从母串中找到一个子序列(可不连续)

子序列的价值为

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


substr为找到的子序列。

id[i]为序列中第i个字符在原串中的位置。

w[id[i]][id[j]]为子序列中第i个字符与第j个字符映射到矩阵中的价值。

这样累加起来就是子序列的价值

子序列的花费为

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

TotalCost=∑9i=0cost[i]

x为0~9

kx为子序列中包含的x这个数字的个数。

找到最大的val−cost

最大权闭合图问题。。

赛后去补,知道了这种有制约关系的流量问题可以用最大权闭合图搞。

然后最大权闭合图问题转化为求最小割的问题。求最小割用最小割容量=最大流,即可将问题转化为求最大流的问题。

然后最大利益=所有点正权值之和-最小割。

至于证明……慢慢啃把=。=、

总之以后遇到类似的题应该会往那里想。

之后主要是建图。

这里就拿样例举个栗子

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



没安啥优美的作图工具。。。凑活看吧=。=、

大体方式就是源点与盈利连接

汇点与花费连接。

之后用最大权闭合图的那套证明,可得到

最大利益=所有点正权值之和-最小割(可用最大流求得)。

Pij表示选择的串包含i->j这一关系,也就是包含原串中第i和第j个字母。如果要得到这一价值的话,就要连通si与sj。如果连通si,那么si这个数字就要有。这样就构成了这个图。

连通Pij的价值为w[i][j]+w[j][i]

每选择一个数字(假设是’0’),就要亏损a[0],由于第一次亏损b[0].

因此’0’到源点价值为b[0]。但由于s中的数字0如果被选中,既走向汇点又走向’0’,因此’0’走向汇点的价值应为(b[0]−a[0])(第一次亏损b[0])

代码如下:

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 10000;
const int mod = 1e9+7;
const double eps = 1e-8;

struct Edge
{
int v,w,next;
Edge(){}
Edge(int _v,int _w,int _next):v(_v),w(_w),next(_next){}
};

int head[233333];
Edge eg[2333333];
int tp;
int a[111],b[111];
int mat[111][111];
char str[1111];
int n,st,en;

void Add(int u,int v,int f)
{
eg[tp] = Edge(v,f,head[u]);
head[u] = tp++;
eg[tp] = Edge(u,0,head[v]);
head[v] = tp++;
}

int gap[233333];
int dis[233333];
int pre[233333];
int cur[233333];
int tot;

int sap()
{
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
memset(pre,-1,sizeof(pre));
memset(cur,-1,sizeof(cur));

gap[0] = n;
int u,v,flow,ans;

flow = INF;
u = pre[0] = 0;
ans = 0;

while(dis[0] < en)
{
for(int &i = cur[u]; i != -1; i = eg[i].next)
{
if(eg[i].w && dis[eg[i].v]+1 == dis[u]) break;
}

if(cur[u] != -1)
{
v = eg[cur[u]].v;
flow = min(flow,eg[cur[u]].w);
pre[v] = u;
u = v;

if(u == en)
{
for(; u != 0; u = pre[u])
{
eg[cur[pre[u]]].w -= flow;
eg[cur[pre[u]]^1].w += flow;
}
ans += flow;
flow = INF;
}
}
else
{
//printf("%d %d %d %d %d----\n",en,u,ans,tot,dis[0]);
int mn = n;

for(int i = head[u]; i != -1; i = eg[i].next)
{
//printf("%d %d %d\n",eg[i].v,eg[i].w,dis[eg[i].v]);
if(eg[i].w && dis[eg[i].v] < mn)
{
mn = dis[eg[i].v];
cur[u] = i;
}
}

//printf("----%d\n",gap[dis[u]]);
if(!(--gap[dis[u]])) break;
dis[u] = mn+1;
//  printf("%d\n",mn+1);
gap[dis[u]]++;
//puts("1");
u = pre[u];
}
}
//printf("%d\n",ans);
return ans;
}

#ifdef debug
bool vis[11111];
void prt(int u,int blank)
{
vis[u] = 1;
//printf("%d---",u);
if(u == 0) puts("scr---");
else if(u == en) puts("end---");
else
{
if(u <= n) printf("pt%d",u);
else if(u <= n*n+n) printf("pt%d %d",u%n? u/n: (u-1)/n,u%n? u%n: n);
else printf("Num%d",u-(n*n)-n-1);
puts("");
}

if(u == 315 || u == 17 || u == 4)
for(int i = head[u]; i != -1; i = eg[i].next)
{
int v = eg[i].v;
if(v == 0) puts("scr");
else if(v == en) printf("->end:%d\n",eg[i].w);
else
{
if(v <= n) printf("->pt%d:%d",v,eg[i].w);
else if(v <= n*n+n) printf("->pt%d %d:%d",v%n? v/n: (v-1)/n,v%n? v%n: n,eg[i].w);
else printf("->Num%d:%d",v-(n*n)-n-1,eg[i].w);
puts("");
}
}

for(int i = head[u]; i != -1; i = eg[i].next)
{
if(vis[eg[i].v]) continue;
prt(eg[i].v,blank+1);
}
}
#endif

int solve()
{
memset(head,-1,sizeof(head));
tp = 0;
tot = 0;

st = 0;
en = (n+1)*n+11;

for(int i = 0; i <= 9; ++i)
{
scanf("%d%d",&a[i],&b[i]);
Add(i+(n+1)*n+1,en,b[i]-a[i]);
}

for(int i = 1; i <= n; ++i)
{
Add(i,str[i]-'0'+(n+1)*n+1,INF);
Add(i,en,a[str[i]-'0']);
for(int j = 1; j <= n; ++j)
{
scanf("%d",&mat[i][j]);
if(i > j)
{
Add(0,j*n+i,mat[i][j]+mat[j][i]);
Add(j*n+i,i,INF);
Add(j*n+i,j,INF);
}
tot += mat[i][j];
}
}

#ifdef debug
memset(vis,0,sizeof(vis));
prt(0,0);
#endif
n = (n+1)*n+12;
return tot-sap();
}

int main()
{
#ifdef debug
fread("1009.in");
//fwrite("");
#endif

int t;

scanf("%d",&t);

for(int z = 1; z <= t; ++z)
{
scanf("%d%s",&n,str+1);

printf("Case #%d: %d\n",z,solve());
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: