acm-(dp、最小树形图)Sichuan State Programming Contest 2011 I.Smart Typist

acm-(dp、最小树形图)Sichuan State Programming Contest 2011 I.Smart Typist
acm-(dp、最小树形图)Sichuan State Programming Contest 2011 I.Smart Typist
传送门

首先容易发现把字符串 x x x通过替换方式变成字符串 y y y会有一个代价 w [ x ] [ y ] w[x][y] w[x][y],这个可以利用dp来计算,如果新建字符串来产生字符串 x x x,则会有个代价 w [ x ] w[x] w[x],由于顺序是任意安排的,并且要求代价总和最小,不妨考虑对任意 i , j i,j i,j字符串建立 i → j i\rightarrow j i→j和 j → i j\rightarrow i j→i边,权值分别为 w [ i ] [ j ] , w [ j ] [ i ] w[i][j],w[j][i] w[i][j],w[j][i],然后考虑新建一个源点 n + 1 n+1 n+1,然后从源点出发对于任意字符串 i i i建立 o → i o\rightarrow i o→i边,权值为 w [ i ] w[i] w[i]。然后以源点为根跑一下最小树形图即可,得到的权值之和恰好为题目所述的代价。

#include <bits/stdc++.h>
#define FOR(i,a,b) for(register int i=a;i<b;++i)
#define ROF(i,a,b) for(register int i=a;i>=b;--i)
using namespace std;

typedef long long ll;
const int maxn = 55;
const int inf = 2147483647;
int a,b,val[26],dp[maxn][maxn];
string s[maxn];
struct Edge{
    int u,v,w;
}e[maxn*maxn];
int cal(int x,int y){
    swap(x,y);
    for(int i=0;i<s[x].length()+1;++i)
    for(int j=0;j<s[y].length()+1;++j)dp[i][j]=inf/4;
    dp[0][0]=0;
    for(int i=0;i<s[y].length();++i)dp[0][i+1]=b*(i+1);
    for(int i=0;i<s[x].length();++i)dp[i+1][0]=dp[i][0]+val[s[x][i]-'a'];
    for(int i=0;i<s[x].length();++i){
        for(int j=0;j<s[y].length();++j){
            if(s[x][i]==s[y][j])dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j]);
            dp[i+1][j+1]=min(dp[i+1][j+1],dp[i+1][j]+b);
            dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j+1]+val[s[x][i]-'a']);
        }
    }
    return dp[s[x].length()][s[y].length()]+a;
}
int cal(int x){
    int ans=0;
    for(int i=0;i<s[x].length();++i){
        ans+=val[s[x][i]-'a'];
    }
    return ans;
}

int n,m,r,fa[maxn],id[maxn],vis[maxn],ine[maxn];
void addedge(int u,int v,int w){
    e[++m]=Edge{u,v,w};
}
ll zhuliu(){
    ll ans=0;
	int cnt=0;
	while(true){
		FOR(i,1,n+1)vis[i]=id[i]=0,ine[i]=inf;
		FOR(i,1,m+1){
			int u=e[i].u,v=e[i].v,w=e[i].w;
			if(ine[v]>w && u!=v){
				ine[v]=w;
				fa[v]=u;
			}
		}
		cnt=ine[r]=0;
		FOR(i,1,n+1){
			if(ine[i]==inf){
                return 0;

			}
			if(i==r)continue;
			ans+=(ll)ine[i];
			int u;
			for(u=fa[i];u!=r && !id[u] && vis[u]!=i;u=fa[u])vis[u]=i;
			if(u!=r && !id[u]){
				id[u]=++cnt;
				for(register int v=fa[u];v!=u;v=fa[v])id[v]=cnt;
			}
		}
		if(!cnt)return ans;
		FOR(i,1,n+1)if(!id[i])id[i]=++cnt;
		FOR(i,1,m+1){
			int last=ine[e[i].v];
			if((e[i].u=id[e[i].u])!=(e[i].v=id[e[i].v]))e[i].w-=last;
		}
		n=cnt;
		r=id[r];
	}
	return ans;
}
int main(){
    int t,kase=0;
    cin>>t;
    while(t--){
        cin>>a>>b;
        for(int i=0;i<26;++i)cin>>val[i];
        m=0;
        cin>>n;
        for(int i=1;i<=n;++i)cin>>s[i];
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                if(i==j)continue;
                int w;
                addedge(i,j,w=cal(i,j));
            }
        }
        for(int i=1;i<=n;++i){
            addedge(n+1,i,cal(i));
        }
        n++;
        r=n;
        printf("Case #%d: %lld\n",++kase,zhuliu());
    }
}

上一篇:AtCoder Grand Contest 049A - Erasing Vertices


下一篇:AtCoder Beginner Contest 188 F - +1-1x2 思维题