题目:http://codeforces.com/problemset/problem/706/C
解法一,搜索
<strong><span style="font-size:18px;">#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const __int64 INF=0x3f3f3f3f3f3f3f3f;
__int64 a[maxn][4],c[maxn],n;
__int64 Cos[maxn][4];
char s11[maxn],s12[maxn],s21[maxn],s22[maxn];
__int64 dfs(__int64 I,__int64 J){
//已经遍历过,不需要再遍历
if(Cos[I][J]>-2)
return Cos[I][J];
//当前的两个字符串可以满足字典序排列,根据后一个字符串的正逆,向下遍历
if(a[I][J]){
__int64 r1,r2;
if(J==0 || J==2){//第二个字符串为正序的时候,第二个字符串向下遍历当该字符串属于正序的情况
r1=dfs(I+1,0);
r2=dfs(I+1,1);
}
else{//第二个字符串为逆序的时候,第二个字符串向下遍历当该字符串属于逆序的情况
r1=dfs(I+1,2);
r2=dfs(I+1,3);
}
if(r1==-1 && r2==-1){//结果全是-1,不存在满足的字符串排列
Cos[I][J]=-1;
}
else{//结果不全为-1,留下开销最小且大于-1的
Cos[I][J]=INF;
if(Cos[I][J]>r1 && r1>-1)
Cos[I][J]=r1;
if(Cos[I][J]>r2 && r2>-1)
Cos[I][J]=r2;
if(J>1)//前一个字符串为逆序,需增加逆序的额外开销
Cos[I][J]+=c[I];
}
return Cos[I][J];
}
else{//相邻字符串的形态不能满足字典序排列
return Cos[I][J]=-1;
}
}
int main(){
__int64 i,j;
scanf("%I64d",&n);
for(i=0;i<n;i++){
scanf("%I64d",&c[i]);
}
//获取字符串的正逆序,sx1为正序,sx2位逆序
scanf("%s",s11);
memcpy(s12,s11,strlen(s11)*sizeof(char)+1);
reverse(s12,s12+strlen(s12));
for(i=0;i<n-1;i++){
scanf("%s",s21);
memcpy(s22,s21,strlen(s21)*sizeof(char)+1);//这里一定要+1,否则'\0'没有复制上去,S22在原本有字符串的情况下会出错
reverse(s22,s22+strlen(s22));
//构造关系矩阵 s1x ,s2x分别代表相邻前后的两个字符串,a[i][x]=1代表的前后两个字符串在相应的正逆下满足字典序排列,0~3分别为 正正、正逆,逆正、逆逆
if(strcmp(s11,s21)<=0)
a[i][0]=1;
if(strcmp(s11,s22)<=0)
a[i][1]=1;
if(strcmp(s12,s21)<=0)
a[i][2]=1;
if(strcmp(s12,s22)<=0)
a[i][3]=1;
strcpy(s11,s21);
strcpy(s12,s22);
}
//边界处理
a[i][0]=a[i][1]=a[i][2]=a[i][3]=1;
//Cos[i][x]数组代表的是第i个字符串的相应序到最后一个字符串满足字典序排列的最小支出,-INF代表还未求出
for(i=0;i<n;i++){
Cos[i][0]=Cos[i][1]=Cos[i][2]=Cos[i][3]=-INF;
}
__int64 ans=INF;
for(j=0;j<4;j++){
if(ans > dfs(0,j) && dfs(0,j)>-1)
ans=dfs(0,j);
}
printf("%I64d\n",ans==INF? -1 : ans);
return 0;
}</span></strong>
<span style="font-size:18px;"><strong>#include<iostream>
#include<bits/stdc++.h>
#define min(a,b) (a)<(b)? (a):(b)
using namespace std;
const int maxn=1e5+5;
const __int64 INF=0x3f3f3f3f3f3f3f3f;
__int64 c[maxn],n;
__int64 dp[maxn][2];
char s11[maxn],s12[maxn],s21[maxn],s22[maxn];
int main(){
__int64 i,j;
scanf("%I64d",&n);
for(i=0;i<n;i++){
scanf("%I64d",&c[i]);
}
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
dp[0][1]=c[0];
//s11,s12为前面字符串的正序和逆序,s21,s22为后面字符串的正序和逆序
scanf("%s",s11);
memcpy(s12,s11,strlen(s11)*sizeof(char)+1);
reverse(s12,s12+strlen(s12));
for(i=0;i+1<n;i++){
scanf("%s",s21);
memcpy(s22,s21,strlen(s21)*sizeof(char)+1);
reverse(s22,s22+strlen(s22));
//dp[i+1][0]=min(dp[i][0],dp[i][1])
if( dp[i+1][0]>dp[i][0] && strcmp(s11,s21)<1 )
dp[i+1][0]=dp[i][0];
if(dp[i+1][0]>dp[i][1] && strcmp(s12,s21)<1 )
dp[i+1][0]=dp[i][1];
//dp[i+1][1]=min(dp[i][0]+c[i+1],dp[i][1]+c[i+1])
if(dp[i+1][1]>dp[i][0]+c[i+1] && strcmp(s11,s22)<1)
dp[i+1][1]=dp[i][0]+c[i+1];
if(dp[i+1][1]>dp[i][1]+c[i+1] && strcmp(s12,s22)<1)
dp[i+1][1]=dp[i][1]+c[i+1];
strcpy(s11,s21);
strcpy(s12,s22);
}
__int64 ans=INF;
ans=min(dp[n-1][0],dp[n-1][1]);
printf("%I64d\n",ans<INF? ans : -1);
return 0;
}
</strong></span>