[Underfail][CodeForces.717.G][费用流]
来源:互联网 发布:美国大数据公司 年薪 编辑:程序博客网 时间:2024/06/06 02:33
题目
Bubble Cup 9 - Finals [Online Mirror]
题意
你进入了一个地下城, 有两只骷髅有事没事就给你出题, 说好的邂逅呢?
这一天, 有一只骷髅给了你一个长为n的字符串, 和m个用来匹配的字符串, 每个字符串有个权重p分, 每个位置的字符都只能用x次, 问你最多能拿几分
用例解析就是:
分析
看上去是KMP, 其实是一道费用流, 建边如图
相邻两个字符之间建一条费用为0, 流量为x的边, 表示从源点到汇点最多可以流过x的流量.
在可匹配的子串的头和尾尾+1建立一条费用为-p, 流量为1的边.
最后用最小费用流跑一遍就OK了.
AC代码
第一次TLE, 建边的时候只在匹配的子串的头和尾建边, 遇到用例是单字符的情况, 建了自环QAQ.
第二次WA, 建点只建到上图的END, 总流量计算有误orz, 多添加一个节点(汇点)后AC.
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<cstdlib>#include<queue>#include<vector>#include<stack>#include<string>using namespace std;#define lson l,m,x<<1#define rson m+1,r,x<<1|1const int INF = 0x3fffffff;const int dx[4] = { 1, -1, 0, 0 };const int dy[4] = { 0, 0, 1, -1 };const double eps = 1e-8;const int maxn = 666;const int N = 1010;//点const int M = 2 * 10010;//边const int inf = 1000000000;struct Node {//边,点f到点t,流量为c,费用为wint f, t, c, w;}e[M];int next1[M], point[N], dis[N], q[N], pre[N], ne;//ne为已添加的边数,next,point为邻接表,dis为花费,pre为父亲节点bool u[N];void init();void add_edge(int f, int t, int d1, int d2, int w);void MCMF(int s, int t, int n, int &flow, int &cost);char crossword[506];//char word[106][506];//next数组(prefix数组)//输入待存的空数组next, 待匹配的数组p, 和p数组的长度lenvoid cptnext(int next[], char p[], int len) {int lolp = 0;//length of longest prefixnext[1] = 0;for (int nocm = 2; nocm < len + 1; nocm++) {while (lolp > 0 && p[lolp] != p[nocm - 1])lolp = next[lolp];if (p[lolp] == p[nocm - 1])lolp++;next[nocm] = lolp;}}int main() {//ios::sync_with_stdio(false);freopen("in.txt", "r", stdin);//freopen("out.txt", "w", stdout);int n;while (scanf("%d", &n) != EOF) {scanf("%s", crossword);init();int m;scanf("%d", &m);for (int i = 0; i < m; i++) {char word[506];scanf("%s", word);int p;scanf("%d", &p);int prefix[506];cptnext(prefix, word, strlen(word));//字符串匹配int nocm = 0;for (int j = 0; j < n; j++) {while (nocm > 0 && word[nocm] != crossword[j])nocm = prefix[nocm];if (word[nocm] == crossword[j])nocm++;if (nocm == strlen(word)) {//建一条匹配字符串头至尾的边add_edge(j - nocm + 1, j + 1, 1, 0, -p);}}}int x;scanf("%d", &x);for (int i = 0; i <= n; i++) {add_edge(i, i + 1, x, 0, 0);}int flow = 0, cost = -inf;MCMF(0, n + 1, n + 2, flow, cost);printf("%d\n", -cost);}return 0;}//建图前运行init()//节点下标从0开始//加边时运行add_edge(a,b,c,0,d)表示加一条a到b的流量为c花费为d的边(注意花费为单位流量花费)//特别注意双向边,运行add_edge(a,b,c,0,d),add_edge(b,a,c,0,d)较好,不要只运行一次add_edge(a,b,c,c,d),费用会不对。//求解时代入MCMF(s,t,n,v1,v2),表示起点为s,终点为t,点数为n的图中,最大流为v1,最大花费为v2void init(){memset(point, -1, sizeof(point)); //邻接表初始化 ne = 0;}//f到t的一条边,流量为d1,反向流量d2,花费w,反向边花费-w(可以反悔)void add_edge(int f, int t, int d1, int d2, int w){e[ne].f = f, e[ne].t = t, e[ne].c = d1, e[ne].w = w; //最大流用dfs 自带回溯 所以不需要记录每一条边的起点 这里费用流多记录一个变量方便回溯修改流量。next1[ne] = point[f], point[f] = ne++;e[ne].f = t, e[ne].t = f, e[ne].c = d2, e[ne].w = -w;next1[ne] = point[t], point[t] = ne++;}bool spfa(int s, int t, int n){int i, tmp, l, r;memset(pre, -1, sizeof(pre));for (i = 0; i < n; ++i)dis[i] = inf; //最短路的初始化dis[s] = 0;q[0] = s;l = 0, r = 1;u[s] = true;while (l != r) {tmp = q[l];l = (l + 1) % (n + 1); //手写模拟循环队列u[tmp] = false;for (i = point[tmp]; i != -1; i = next1[i]) {if (e[i].c && dis[e[i].t] > dis[tmp] + e[i].w) { //经典的循环队列模拟spfa dis[e[i].t] = dis[tmp] + e[i].w;pre[e[i].t] = i;if (!u[e[i].t]) {u[e[i].t] = true;q[r] = e[i].t;r = (r + 1) % (n + 1);}}}}if (pre[t] == -1)return false;return true;}//起点s,终点t,点数n,最大流flow,最小花费cost// 该做法是比较常见的不建辅助网络 在原网络上每一次选择费用最小的路径进行增广 直到找不到可以增广的路径 void MCMF(int s, int t, int n, int &flow, int &cost) {int tmp, arg;flow = cost = 0;while (spfa(s, t, n)) //每一次如果求最短路的过程中访问到了汇点 那么pre[t]!=-1 就继续往下进行{arg = inf, tmp = t;while (tmp != s) { //从终点一直回溯到起点 求出路径上的最小流量arg = min(arg, e[pre[tmp]].c);tmp = e[pre[tmp]].f;}tmp = t;while (tmp != s) { //再次回溯 修改流量e[pre[tmp]].c -= arg;e[pre[tmp] ^ 1].c += arg;tmp = e[pre[tmp]].f;}flow += arg; //修改最大流cost += arg * dis[t]; //修改最小费用}}
1 0
- [Underfail][CodeForces.717.G][费用流]
- 【费用流】[CodeForces - 717G]Underfail
- codeforces 717 G. Underfail(费用流,好题)
- [无源汇最大费用可行流 差分费用流] Codeforces 717G Bubble Cup 9 - Finals G. Underfail
- Codeforces 164C 费用流
- codeforces 730I (费用流)
- codeforces 277E 最小费用最大流
- Codeforces 237E Build String 【费用流】
- Codeforces 362E Petya and Pipes (费用流)
- CodeForces 164C Machine Programming(费用流)
- Codeforces--237E--Build String(最小费用流)
- Codeforces 362 E Petya and Pipes【费用流】好题
- 【Codeforces 739E】 Gosha is hunting【费用流】
- Codeforces 708D 费用流 (呃我们的考试题)
- codeforces 863F Almost Permutation 费用流 好题!
- Codeforces 322D Ciel and Duel【思维+费用流】
- [线性规划 费用流]Codeforces Gym101190D.Delight for a cat
- [模拟费用流] Codeforces Gym101190 NEERC2016M. Mole Tunnels
- UVA 10891 Game of Sum(区间博弈dp)***
- 【原创】堆排序+合并果子+优先队列
- 【堆】这是要搞事情啊——建立
- <堆> 大根堆和小根堆的建立
- 找不到系统文件C:\ProgramData\Oracle\Java\javapath\java.exe
- [Underfail][CodeForces.717.G][费用流]
- poj1321棋盘问题
- 【Maven实战】04 坐标
- HDU 1300 Pearls DP .
- 数据类型
- Webbech学习之getopt_long函数
- Redis深入理解-数据结构篇(1)-简单动态字符串SDS
- 类和对象的基础8——对象指针和对象数组
- 【8】SchedulerListeners