您的位置:首页 > 其它

# USACO4.4 三道题

2016-05-26 21:10 232 查看

USACO4.4 三道题

这次三道题

Shuttle Puzzle 是普通题,可以找规律,可以搜索+剪枝.

Pollutant Control 是网络流,有几个难点需要仔细处理,不能直接套模板

Frame Up 是简单题…递归扫一遍,注意输出

shuttle

N = 3
初始状态: WWW_BBB
目标状态: BBB_WWW


N <= 12

求字典序最小的最小步数…

(找规律可以发现最小步数是N * (N+2))

深搜+剪枝..0s过(可以用规律优化)

(nocow)构造法



根据答案寻找规律(可以证明正确性):

3
3 5 6 4 2 1 3 5 7 6 4 2 3 5 4
2 1 -2 -2 -1 2 2 2 -1 -2 -2 1 2 -1

4
4 6 7 5 3 2 4 6 8 9 7 5 3 1 2 4 6 8 7 5 3 4 6 5
2 1 -2 -2 -1 2 2 2 1 -2 -2 -2 -2 1 2 2 2 -1 -2 -2 1 2 -1

5
5 7 8 6 4 3 5 7 9 10 8 6 4 2 1 3 5 7 9 11 10 8 6 4 2 3 5 7 9 8 6 4 5 7 6
2 1 -2 -2 -1 2 2 2 1 -2 -2 -2 -2 -1 2 2 2 2 2 -1 -2 -2 -2 -2 1 2 2 2 -1 -2 -2 1 2 -1

6
6 8 9 7 5 4 6 8 10 11 9 7 5 3 2 4 6 8 10 12 13 11 9 7 5 3 1 2 4 6 8 10 12 11 9 7 5 3 4 6 8 10 9 7 5 6 8 7
2 1 -2 -2 -1 2 2 2 1 -2 -2 -2 -2 -1 2 2 2 2 2 1 -2 -2 -2 -2 -2 -2 1 2 2 2 2 2 -1 -2 -2 -2 -2 1 2 2 2 -1 -2 -2 1 2 -1

先观察样例数据,如果把还没移动的那一步也算上,那么空格的位置为
4 3 5 6 4 2 1 3 5 7 6 4 2 3 5 4 (n=3,样例)
5 4 6 7 5 3 2 4 6 8 9 7 5 3 1 2 4 6 8 7 5 3 4 6 5 (n=4)
我们凭借极其敏锐的眼光发现这组序列为
435 642 1357 642 35 4 (n=3,样例)
5 46 753 2468 97531 2468 753 46 5 (n=4)
即长度为1,2,3,4,...,n,n+1,n,...,4,3,2,1这样的2n+1组等差序列
我们讨论第1~n+1组序列,这些序列满足
  *公差的绝对值为2
  *奇数组为降序列,偶数组为升序列
  *对于第i组(1<=i<=n+1),若为奇数组则首项为n+i,偶数组则首项为n-i+2
对于第n+2~2n+1组,可以由对称性求出。
输出时从第二组开始即可。


*mike6 不宜用最小割优化算法的最小割…

V<=32,E<=1000的有向图,给出每个割的价值,求最小数目的最小价值割,有多组输出字典序最小的

最大流=最小割中,最大流的意义就不大了…

但是还是要套用最大流算法

这道题尴尬的是输出,因此不能完全套用模板

想了很久去看题解,输出字典序最小的话,那么最后就应该枚举边集

(话说看题解释nocow吵的很开心..都说别人错了并给出范例数据= =)

然后是最小数目的割,观察到E<=1000所以编码优化,存储流信息的时候,
cost = c * 1001 + 1;


然后用一个edge表存边,用邻接矩阵存图,由于V很小,没必要用邻接表优化,直接枚举就行

(话说我也觉得一开始学这个算法就应该用枚举)

输出最小价值就是cost/1001,最小割数就是cost%1001.(其实这个没有先后关系吧.)

一堆WA给第一个网络流的bug警示

Dinic算法

bfs时候起始点距离应该标记为1,不然可能有回边,这样会很麻烦

dfs时候深搜下去是
temp = dfs(p,min(ca,cap[fr][p]));
然后当前位置矩阵和容量-temp,对称位置矩阵+temp.ca不能写成temp

输出字典序最小,那么应该设一个变量标记输出了多少个了,完成即退出

算法简要描述

bfs确定每一点到源点最近距离,源点为1.

如果终点距离存在,深搜扩展(源点,inf),否则退出算法

深搜:

如果是终点返回扩展量

否则枚举可行边,进行扩展.基本模板如下

long long temp,cnt = 0;
for (int p = 1; p <= totNode; p++) {
if (dis[p] == dis[fr] + 1 && cap[fr][p]) {
//cout << temp << " " << ca << endl;
temp = dfs(p,min(ca,cap[fr][p]));
ca   -= temp;
cap[fr][p] -= temp;
cap[p][fr] += temp;
cnt += temp;
}
}


min_cut算法

void min_cut(){
//广搜/floodfill包含源点联通区域(联通及f>0)
int cnt = 0;
for (int i = 1; i <= n; i+=2)
if (v[i]) //枚举联通区域每一点,确认割点
for (int j = g[i]; j; j = e[j].nxt)
if (!v[e[j].v] && e[j].f == 0)
ans.push_back(e[j].v);

}




Frame Up

给出一个形如下方的图层覆盖,求覆盖顺序

/*
矩形的边的宽度为 1 ,每条边的长度都不小于 3 。
矩形的每条边中,至少有一部分是可见的。注意,一个角同时属于两条边。
矩形用大写字母表示,并且每个矩形的表示符号都不相同。

30 30
..............................
.OOOOOOOOOYYYYYOO.............
.O....PPPPYPPPYPOPP...........
.O....P...Y...Y.O.P...........
.O....P...Y...Y.O.P...........
.O....P...Y...Y.O.P...........
.O....P...Y...Y.O.P...........
.O....P...Y...Y.O.P...........
.O....P...Y...Y.O.P...........
.O....P...Y...Y.O.P...........
.OOOOOOOOOYOOOYOEEEEEEEEE.....
......PPPPYPPPYPEPP.....E.....
..........Y...Y.E.......E.....
..WWWWWWWWWWWWWWWWWTT...E.....
..W...T...Y...Y.E.W.T...E.....
..W...T...Y...Y.E.W.T...E.....
..W...T...Y...Y.E.W.T...E.....
..W...T...YYYYY.EEWEEEEEE.....
UUWWWWWWWWWWWWWWWWW.T.........
U.....TTTTTTTTTTTTQQQQQQQQQQQ.
U....RRRRRRRRRRRRRQRRRRR....Q.
U....R............Q....R....Q.
UIIIIRRRRRRRRRRRRRQRRRRRIIIIQ.
UI................QQQQQQQQQQQ.
UUUUUUUUUUUUUUUUUUU........I..
.IIIIIIIIIIIIIIIIIIIIIIIIIII..
..............................
..............................
..............................
..............................

*/


本来想找标志的..看到规则这道题就很简单了

就是要注意输出顺序

读入的时候标记每个字符的最上最左最右最下….check是否为当前字符或者已经用了的字符

有一点栈的思想
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: