light oj 1073 状态压缩dp+输出字典序最小的解

算是比较基本的题,不忍直视的搓代码,string乱搞后惨不忍睹,调了好久终于AC,代码能力弱成渣。

做法:给你的一些串中,你先暴力去掉一些无用的子串, 比方有aaaa 和aa,那aa就没用了,去掉

然后从下往上放字符串(注意方向,为了输出字典序最小),我的val[i][j]表示串i在下,串j在上所增加的str[i]的前缀长度   如  aabb  bbcccc, 那前缀为aa,长度为2

然后dfs搜出解。string用得太逗比了,这里用char字符串也还可以,写得好就很方便。


附上刚刚AC的代码和以前AC的代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
string str[17];
int n;
bool ok(const string &a, const string &b) {
	int sz =  max<int>(0, b.size()-a.size());
	int i, j, cur;
	for(i = 0; i < sz; i++) {
		cur = i;
		for(j = 0; j < (int)a.size() &&
		cur < (int)b.size()&& a[j] == b[cur]; j++, cur++);
		if(j == (int)a.size()) return 1;
	}
	return 0;
}
int cal(const string &a , const string &b) {
	int i, j, cur;
	int ret = b.size();
	for(i = 0; i < (int)b.size(); i++) {
		cur = i;
		for(j = 0; j < (int)a.size() &&
		cur < (int)b.size() && a[j] == b[cur]; j++, cur++);
		if(cur == (int)b.size())
			ret = min<int>(ret, i);
	}
	return ret;
}
int val[17][17];
int dp[17][1<<17];
void out(int pos, int st) {
	if(st == (st&-st)) {
		//cout << "nice" << endl;
		cout << str[pos];
		return;
	}
	int j, cur = -1;
	string tp = "Z";
	int ans = -1;
	for(j = 0; j < n; j++) if(j != pos && (st&(1<<j))) {
	//	cout << "j " << j << endl;
		if(dp[j][st^(1<<pos)] + val[j][pos] == dp[pos][st]) {
		//	cout << "first " << str[pos].size()-val[j][pos];
			string res = str[j].substr(str[pos].size()-val[j][pos], str[j].size());
		//	cout << "res~~~~" << res << endl;
			if(res < tp) {
				tp = res;
				cur = j;
				ans = val[j][pos];
			}
		}
	}
//	cout << "ans = " << ans << endl;
	//cout << "~~~~~~~~~~~~~" << endl;
	cout << str[pos].substr(0, val[cur][pos]);
	//cout << "cur~~~" <<cur<< endl;
	out(cur, st^(1<<pos));
}
int full;
int main() {
	int i, j, k, cas, ca = 1;
	cin >> cas;
	while(cas--) {
		cin >> n;
		for(i = 0; i < n; i++)
			cin >> str[i];
		int m = 0;
		for(i = 0; i < n; i++) {
			for(j = 0; j < n; j++)if(j != i)
				if(ok(str[i], str[j])) break;
			if(j == n)
				str[m++] = str[i];
		}

		n = m;
		full = (1<<n)-1;
	//	for(i = 0; i < n; i++)
	//		cout << str[i] << endl;
		for(i = 0; i < n; i++)
			for(j = 0; j < n; j++) if(i != j) {
				val[i][j] = cal(str[i], str[j]);
			//	printf("val[%d][%d] = %d\n", i, j, val[i][j]);
			}
		for(i = 0; i < n; i++)
			for(j = 0; j < (1<<n); j++)
				dp[i][j] = -1;
		for(i = 0; i < n; i++)
			dp[i][1<<i] = str[i].size();
		for(j = 0; j < (1<<n); j++)
			for(i = 0; i < n; i++) if(~dp[i][j]) {
				for(k = 0; k < n; k++) if(!(j&(1<<k))) {
					int inc = dp[i][j] + val[i][k];
					//cout << inc << endl;
					if(dp[k][j|(1<<k)] == -1 || dp[k][j|(1<<k)] > inc) {
						dp[k][j|(1<<k)] = inc;
					}
				}
			}
		//for(i = 0; i < n; i++)
		//	cout << "i = " << dp[i][full] << endl;
		int pos = 0;
	//	cout << (str[1] < str[2]) << endl;
	//	cout << n  <<"~~~" << endl;
		for(i = 1; i < n; i++)
			if( dp[i][full] < dp[pos][full] ||
					(dp[i][full] == dp[pos][full] && str[i] < str[pos])) {
				pos = i;
			//	cout << "update" << pos << endl;
			}
		cout << "Case " << ca++ << ": ";
	//	cout << "pos = " << pos << endl;
	//	cout << "~~~" << dp[pos][full] << endl;
		//cout << full << endl;
		out(pos, full);
		cout << endl;
	}
	return 0;
}
/*
1
10
TTTT
TT
T
T
T
GCGCG
CCCC
C
C
C
 */


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf = 1e9;
struct node {
    int len;
    char s[103];
    void in() {
        scanf("%s", s);
        len = strlen(s);
    }
}p[16];
int n;
int cnt[16][16];
int two[18];
int dp[15][33333];
int Log[33333];
int f[101];
inline void getfail(char *s, int &la) {
    int i, j = 0;
    f[0] = f[1] = 0;
    for(i = 1; i < la; i++) {
        while(j && s[i] != s[j]) j = f[j];
        if(s[i] == s[j]) j++;
        f[i+1] = j;
    }
}
inline bool kmp(char *s, char *t, int &la, int &lb) {
    int i, j = 0;
    getfail(t, lb);
    for(i = 0; i < la; i++) {
        while(j && s[i] != t[j]) j = f[j];
        if(s[i] == t[j]) j++;
        if(j == lb) return 1;
    }
    return 0;
}
inline bool ok(int &x, int &y) {
    int i, j;
    for(i = 0; i < p[x].len; i++) {
        for(j = 0; j < p[y].len && i+j < p[x].len && p[x].s[i+j] == p[y].s[j]; j++);
        if(j == p[y].len) return 1;
    }
    return 0;
}
bool cmp1(const node &a, const node &b) {
    return a.len > b.len;
}
bool cmp2(const node &a, const node &b) {
    return strcmp(a.s, b.s) < 0;
}
inline void out(int pos, int st) {
    if(!st) {
        puts(p[pos].s);
        return;
    }
    int i;
    int ans = -1, idx;
    for(int x = ~two[n]&st; x; x -= x&-x) {
        i = Log[x&-x];
        int inc = dp[i][st^two[i]] + p[pos].len - cnt[pos][i];
        if(ans == -1 || ans > inc || (ans == inc && strcmp(&p[i].s[cnt[pos][i]],&p[idx].s[cnt[pos][idx]]) < 0) ) {
            ans = inc;
            idx = i;
        }
    }
    int end = p[pos].len - cnt[pos][idx];
    for(i = 0; i < end; i++)
        printf("%c", p[pos].s[i]);
    out(idx, st^two[idx]);
}
int main() {
    int i, j, x, y, cas;
    two[0] = 1; Log[0] = -1;
    for(i = 1; i <= 16; i++) two[i] = two[i-1] << 1;
    for(i = 1; i < two[15]; i++) Log[i] = Log[i>>1] + 1;
    scanf("%d", &cas);
    for(int ca = 1; ca <= cas; ca++) {
        scanf("%d", &n);
        for(i = 0; i < n; i++) p[i].in();
        sort(p, p+n, cmp1);
        int m = 1;
        for(i = 1; i < n; i++) {
            getfail(p[i].s, p[i].len);
            for(j = 0; j < m; j++) if(kmp(p[j].s, p[i].s, p[j].len, p[i].len)) break;
            if(j == m) {
                p[m++] = p[i];
            }
        }
        n = m;
        sort(p, p+n, cmp2);

        for(i = 0; i < n; i++) {
            for(j = 0; j < n; j++) if(i != j){
                cnt[i][j] = 0;
                for(x = 0; x < p[i].len; x++) {
                    int tp = 0;
                    for(y = 0; y < p[j].len && x+y < p[i].len && p[i].s[x+y] == p[j].s[y]; y++) tp++;
                    if(x+y == p[i].len) cnt[i][j] = max(cnt[i][j], tp);
                }
            }
        }
        printf("Case %d: ", ca);
        for(i = 0; i < n; i++)
            for(j = 0; j < two[n]; j++)
                dp[i][j] = -1;

        int ans = -1, pos;
        for(i = 0; i < n; i++)
            dp[i][0] = p[i].len;

        for(j = 0; j < two[n]; j++) {
            for(i = 0; i < n; i++) if(~dp[i][j]){
                for(int xx = (two[n+1]-1)^(~two[n]&j); xx; xx -= xx&-xx) {
                    x = Log[xx&-xx];
                    if(i == x) continue;
                    int inc = dp[i][j] + p[x].len - cnt[x][i];
                    if(dp[x][j|two[i]] == -1 || dp[x][j|two[i]] > inc) {
                        dp[x][j|two[i]] = inc;
                    }
                }
            }
        }

        for(i = 0; i < n; i++) {
            if(ans == -1 || ans > dp[i][(two[n]-1)^two[i]]) {
                ans = dp[i][(two[n]-1)^two[i]];
                pos = i;
            }
        }
        out(pos, (two[n]-1)^two[pos]);
    }
}


你可能感兴趣的:(light oj 1073 状态压缩dp+输出字典序最小的解)