盛夏的果实 发表于 2021-7-21 11:18:16

hdu 5772 String problem 最大权闭合子图

DescriptionThis 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=0,kx=0cost=ax∗(kx−1)+bx,kx≠0TotalCost=∑i=09costThe 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 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.InputThe 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<=50OutputEach test output one line “Case #x: y” , where x is the case number ,staring from 1. y is the Maximum score.Sample Input1
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 0Sample OutputCase #1: 3Hint
we can choose “15”,id[]={1,3} then Value=w+w=7,
Total_Cost=2+2=4,Score=7-4=3Hint题意给你一个字符串,只含有数字。你需要选择出一个子序列,使得这个子序列的权值最大。这个子序列如果这个数字第一次出现就ans-=bx,否则就-=ax然后如果第i个字符和第j个字符都在子序列里面,那么ans+=w问你最大ans是多少题解:比较显然的就是最大闭合子图了,这个跑网络流就是了。标准题解:网络流:最大权闭合子图。
思路如下:首先将点分为3类第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w+w(表示得分)第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a] (表示要花费)第三类:对于10种字符拆出10个点,每个点的权值为 -(b-a)那么我们可以得到一个关系图 ,对于第一类中的点Pij,如果想要选择Pij,你就必须要选中第二类中的点i和j,对于第二类中的点如果你想选中第i个点,其对应的字符s,那么就必须选中第三类中s 对应的点,因为每个种类的点第一次选中时花费是b],而第二类中花费都是a],一定要补上b]-a],而且只需要补上一次。得到上面的关系图后然后就是普通的最大权闭合子图问题,直接求解即可。但是我们队比较邪,我们先2^10枚举了一下,然后再跑的网络流,但是这样会TLE。于是我们就XJB只搜了后面的几个状态和前面的状态,然后跑网络流就过了……下面代码是我们队的谐星做法,非正解,正解按照前面的思路建图就好了。另外这个图跑ISAP比跑dinic快的多。。。。
代码#include<bits/stdc++.h>
#define Maxn 60009
#define Maxm 400009
#define inf 100000000
#define LL int
using namespace std;
const int MAXN=100000,MAXM=100000;
struct Edge
{
    int v,c,f,nx;
    Edge() {}
    Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {}
} E;
int G,cur,pre,dis,gap,N,sz;
void init(int _n)
{
    N=_n,sz=0; memset(G,-1,sizeof(G)*N);
}
void link(int u,int v,int c)
{
    E=Edge(v,c,0,G); G=sz++;
    E=Edge(u,0,0,G); G=sz++;
}
int ISAP(int S,int T)
{//S -> T
    int maxflow=0,aug=inf,flag=false,u,v;
    for (int i=0;i<N;++i)cur=G,gap=dis=0;
    for (gap=N,u=pre=S;dis<N;flag=false)
    {
      for (int &it=cur;~it;it=E.nx)
      {
            if (E.c>E.f&&dis==dis.v]+1)
            {
                if (aug>E.c-E.f) aug=E.c-E.f;
                pre=u,u=v; flag=true;
                if (u==T)
                {
                  for (maxflow+=aug;u!=S;)
                  {
                        E]].f+=aug;
                        E^1].f-=aug;
                  }
                  aug=inf;
                }
                break;
            }
      }
      if (flag) continue;
      int mx=N;
      for (int it=G;~it;it=E.nx)
      {
            if (E.c>E.f&&dis.v]<mx)
            {
                mx=dis.v]; cur=it;
            }
      }
      if ((--gap])==0) break;
      ++gap=mx+1]; u=pre;
    }
    return maxflow;
}
bool bfs(int S,int T)
{
    static int Q; memset(dis,-1,sizeof(dis)*N);
    dis=0; Q=S;
    for (int h=0,t=1,u,v,it;h<t;++h)
    {
      for (u=Q,it=G;~it;it=E.nx)
      {
            if (dis.v]==-1&&E.c>E.f)
            {
                dis=dis+1; Q=v;
            }
      }
    }
    return dis!=-1;
}
int dfs(int u,int T,int low)
{
    if (u==T) return low;
    int ret=0,tmp,v;
    for (int &it=cur;~it&&ret<low;it=E.nx)
    {
      if (dis.v]==dis+1&&E.c>E.f)
      {
            if (tmp=dfs(v,T,min(low-ret,E.c-E.f)))
            {
                ret+=tmp; E.f+=tmp; E.f-=tmp;
            }
      }
    }
    if (!ret) dis=-1; return ret;
}
int dinic(int S,int T)
{
    int maxflow=0,tmp;
    while (bfs(S,T))
    {
      memcpy(cur,G,sizeof(G)*N);
      while (tmp=dfs(S,T,inf)) maxflow+=tmp;
    }
    return maxflow;
}

struct st
{
    int u,v;
    LL value;
}e;
int cost;
int mp;
int a,b,nn;
int Ans = 0;
string s;
LL get(int zt){
    vector<int> tmp;
    LL sum=0;
    int cccc = 0;
    for(int i=0;i<10;i++){
      if((1<<i)&zt){
            sum-=(b-a);
      }
    }
    for(int i=0;i<s.size();i++){
      int num = s-'0';
      if((1<<num)&zt){
            tmp.push_back(i+1);
            cost=a-'0'];
         //   cout<<i<<" ";
      }
    }
    int m = 1;

    for(int i=0;i<tmp.size();i++){
      for(int j=i+1;j<tmp.size();j++){
            e.u=tmp;
            e.v=tmp;
            e.value=mp]]+mp]];
            sum+=e.value;
            m++;
      }
    }
    if(sum<=Ans)return 0;
    m--;
    init(12000);
    int n = tmp.size();
    for(int i=1;i<=m;i++)
    {
      link(0,i,e.value);
      link(i,m+e.u,inf);
      link(i,m+e.v,inf);
    }
    for(int i=1;i<=n;i++)
      link(tmp+m,m+nn+1,cost]);
    LL ans=ISAP(0,m+nn+1);
    return sum-ans;
}
int cas = 0;
int vvv;
int ccc = 0;
int times = 0 ;

void dfs1(int x,int tmp,int k){
    if(x==10){

      if( (k>=ccc-7||ccc<=2) )Ans=max(Ans,get(tmp));
      return;
    }
    if(vvv)dfs1(x+1,tmp|(1<<x),k+1);
    dfs1(x+1,tmp,k);
}

void solve(){
    memset(vvv,0,sizeof(vvv));
    Ans=0;
    times=0;
    scanf("%d",&nn);
    cin>>s;
    ccc=0;
    for(int i=0;i<s.size();i++){
      if(vvv-'0']==0)ccc++;
      vvv-'0']=1;
    }
    for(int i=0;i<10;i++){
      scanf("%d%d",&a,&b);
    }
    for(int i=1;i<=nn;i++){
      for(int j=1;j<=nn;j++){
            scanf("%d",&mp);
      }
    }

    dfs1(0,0,0);


    cout<<"Case #"<<++cas<<": "<<Ans<<endl;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--)solve();
    return 0;
}

页: [1]
查看完整版本: hdu 5772 String problem 最大权闭合子图