HDU5772 String problem 最大權閉合圖

題目鏈接:點擊打開鏈接

題目大意:有一個長度爲n(n<=100)的串,字符集爲'0'-'9'。現在希望它的一個子序列分數最大,分數定義如下

Score=Value - Cost

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

cost是子序列中的每個字符出現次數有關的函數

對於字符x有

cost[x]=ax(kx1)+bx,kx0


解析:

最大權閉合圖,首先解釋一下什麼是閉合圖。

對於一個有向圖G,所有點的出邊指向的點都在該圖內,則該圖是一個閉合圖。若G的一個子圖滿足閉合圖的定義,則它是G的一個閉合子圖。對於一個有點權的有向圖,最大權閉合圖就是指一個點權之和最大的閉合子圖。

最大權閉合圖可以解決依賴關係問題。

該題因爲權值計算是線性的,所以可以把項進行拆分然後再建圖。


將點分爲3類

第一類:Pij 表示第i個點和第j個點組合的點,那麼Pij的權值等於w[i][j]+w[j][i](表示得分)

第二類:原串中的n個點每個點拆出一個點,第i個點權值爲 –a[s[i]] (表示要花費)

第三類:對於10種字符拆出10個點,每個點的權值爲  -(b[x]-a[x])


最大權閉合圖用網絡流求解,根據原圖建立一個等價的網絡,構建規則如下。

對於點權爲正的節點,從源點連一條容量爲點權的邊到該點,對於點權爲負的邊,從該點連一條容量爲點權絕對值的邊到匯點。原圖中的邊保留,容量爲inf。最大權值即爲圖中所有正點權之和減去最大流。


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cmath>
#include <set>
#include <queue>
#include <map>
#include <bitset>

using namespace std;
typedef long long ll;
const int mod = 1000000007;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const ll INF = 100000000000000000ll;
const int MAXN = 100010;
const int MAXM = 300030;

namespace nwf{
const int N = 10050;
const int M = 100000;
const int INF = 0x3f3f3f3f;
int head[N], cur[N], d[N], st[M], s, e, no;
struct point{
	int u, v, flow, next;
	point(){};
	point(int x, int y, int z, int w):u(x), v(y), next(z), flow(w){};
}p[M];

void add(int x, int y, int z){
	p[no] = point(x, y, head[x], z);	head[x] = no++;
	p[no] = point(y, x, head[y], 0);	head[y] = no++;
}
void init(){
	memset(head, -1, sizeof(head));
	no = 0;
}

bool bfs(){
	int i, x, y;
	queue<int>q;
	memset(d, -1, sizeof(d));
	d[s] = 0;	q.push(s);
	while(!q.empty()){
		x = q.front();	q.pop();
		for(i = head[x]; i != -1; i = p[i].next){
			if(p[i].flow && d[y = p[i].v] < 0){
				d[y] = d[x] + 1;
				if(y == e)	return true;
				q.push(y);
			}
		}
	}
	return false;
}

int dinic(){
	int i, loc, top, x = s, nowflow, maxflow = 0;
	while(bfs()){
		for(i = s; i <= e; i++)	cur[i] = head[i];
		top = 0;
		while(true){
			if(x == e){
				nowflow = INF;
				for(i = 0; i < top; i ++){
					if(nowflow > p[st[i]].flow){
						nowflow = p[st[i]].flow;
						loc = i;
					}
				}
				for(i = 0; i < top; i++){
					p[st[i]].flow -= nowflow;
					p[st[i]^1].flow += nowflow;
				}
				maxflow += nowflow;
				top = loc;	x = p[st[top]].u;
			}
			for(i = cur[x]; i != -1; i = p[i].next)
				if(p[i].flow && d[p[i].v] == d[x] + 1) break;
			cur[x] = i;
			if(i != -1){
				st[top ++] = i;
				x = p[i].v;
			}
			else {
				if(!top)	break;
				d[x] = -1;
				x = p[st[--top]].u;
			}
		}
	}
	return maxflow;
}
}

int a[11],b[11],mat[105][105];
char ss[105];


int main()
{
    int T,cas=1,n;
    cin>>T;
    while(T--){
        scanf("%d%s",&n,ss);
        for(int i = 0;i < 10;i++){
            scanf("%d%d",&a[i],&b[i]);
        }
        for(int i = 0;i < n;i++){
            for(int j = 0;j < n;j++){
                scanf("%d",&mat[i][j]);
            }
        }
        int res = 0;
        nwf::init();
        nwf::s = 0;
        nwf::e = 10+n*n+1;
        int tot = 1;
        for(int i = 0;i < n;i++){
            for(int j = 0;j < n;j++){
                if(i != j){
                    res += mat[i][j];
                    nwf::add(nwf::s,tot,mat[i][j]);
                    nwf::add(tot,n*(n-1)+1+i,inf);
                    nwf::add(tot,n*(n-1)+1+j,inf);
                    tot++;
                }
            }
        }

        for(int i = 0;i < n;i++){
            int id = ss[i]-'0';
            nwf::add(tot,nwf::e,a[id]);
            nwf::add(tot,n*n+1+id,inf);
            tot++;
        }
        for(int i = 0;i < 10;i++){
            if(a[i]>b[i]){
                nwf::add(nwf::s,tot++,a[i]-b[i]);
                res += a[i]-b[i];
            }
            else{
                nwf::add(tot++,nwf::e,b[i]-a[i]);
            }
        }
        int maxflow;
        maxflow = nwf::dinic();
        //printf("%d\n",maxflow);
        //printf("%d\n",tot);
        printf("Case #%d: %d\n",cas++,res-maxflow);
    }
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章