uva 11381(神奇的构图、最小费用最大流)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=29821

思路:首先拆点,每个字符对应的位置拆成i和i+len,然后源点和i连边,容量为1,花费为0,i+len与汇点连边,容量为1,花费为0,然后就是对于那些在P中的字符串连边,容量为1,花费为g[u][v],最后跑最小费最大流即可,然后答案就是len-flow,cost;

  1 #pragma comment(linker, "/STACK:1024000000,1024000000")
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<climits>
  6 #include<cstdlib>
  7 #include<algorithm>
  8 #include<stack>
  9 #include<vector>
 10 #include<queue>
 11 #include<string>
 12 #include<cmath>
 13 #include<set>
 14 using namespace std;
 15 #define inf 1<<30
 16 #define INF 1LL<<60
 17 typedef long long ll;
 18 typedef pair<int,int>PP;
 19 #define MAXN 1111
 20 
 21 struct Edge{
 22     int v,cap,cost,next;
 23 }edge[MAXN*MAXN];
 24 
 25 int len,vs,vt,NE;
 26 int head[MAXN];
 27 
 28 void Insert(int u,int v,int cap,int cost)
 29 {
 30     edge[NE].v=v;
 31     edge[NE].cap=cap;
 32     edge[NE].cost=cost;
 33     edge[NE].next=head[u];
 34     head[u]=NE++;
 35 
 36     edge[NE].v=u;
 37     edge[NE].cap=0;
 38     edge[NE].cost=-cost;
 39     edge[NE].next=head[v];
 40     head[v]=NE++;
 41 }
 42 
 43 int pre[MAXN],cur[MAXN];
 44 bool mark[MAXN];
 45 int dist[MAXN];
 46 
 47 bool spfa(int vs,int vt)
 48 {
 49     memset(mark,false,sizeof(mark));
 50     fill(dist,dist+MAXN,inf);
 51     dist[vs]=0;
 52     queue<int>que;
 53     que.push(vs);
 54     while(!que.empty()){
 55         int u=que.front();
 56         que.pop();
 57         mark[u]=false;
 58         for(int i=head[u];i!=-1;i=edge[i].next){
 59             int v=edge[i].v,cost=edge[i].cost;
 60             if(edge[i].cap>0&&dist[u]+cost<dist[v]){
 61                 dist[v]=dist[u]+cost;
 62                 pre[v]=u;
 63                 cur[v]=i;
 64                 if(!mark[v]){
 65                     mark[v]=true;
 66                     que.push(v);
 67                 }
 68             }
 69         }
 70     }
 71     return dist[vt]<inf;
 72 }
 73 
 74 void MinCostFlow(int vs,int vt)
 75 {
 76     int flow=0,cost=0;
 77     while(spfa(vs,vt)){
 78         int aug=inf;
 79         for(int u=vt;u!=vs;u=pre[u]){
 80             aug=min(aug,edge[cur[u]].cap);
 81         }
 82         flow+=aug,cost+=dist[vt]*aug;
 83         for(int u=vt;u!=vs;u=pre[u]){
 84             edge[cur[u]].cap-=aug;
 85             edge[cur[u]^1].cap+=aug;
 86         }
 87     }
 88     printf("%d %d\n",len-flow,cost);
 89 }
 90 
 91 
 92 char str1[MAXN],str2[MAXN];
 93 int g[MAXN][MAXN];
 94 int main()
 95 {
 96     int _case;
 97     scanf("%d",&_case);
 98     while(_case--){
 99         scanf("%s",str1);
100         len=strlen(str1);
101         memset(g,0,sizeof(g));
102         for(int i=0;i<len-1;i++){
103             int u=str1[i]-'a',v=str1[i+1]-'a';
104             if(!g[u][v]){
105                 g[u][v]=(i+1)*(i+1);
106             }
107         }
108         scanf("%s",str2);
109         len=strlen(str2);
110         vs=0,vt=2*len+1;
111         NE=0;
112         memset(head,-1,sizeof(head));
113         for(int i=0;i<len;i++){
114             Insert(vs,i+1,1,0);
115             Insert(i+1+len,vt,1,0);
116             for(int j=i+1;j<len;j++){
117                 int u=str2[i]-'a',v=str2[j]-'a';
118                 if(g[u][v]){
119                     Insert(i+1,j+1+len,1,g[u][v]);
120                 }
121             }
122         }
123         MinCostFlow(vs,vt);
124     }
125     return 0;
126 }
127 
128 
129 
130 
131     
View Code

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值