USACO 5.4 章节
Canada Tour
题目大意
双向连通图,点从左向右排列,
你需要先从最左的点到最右的点,(过程中只能从左向右走)
然后再从最右的点返回最左的点,(过程中只能从右向左走)
过程中除了最左的点,其它点都至多能经过一次
求最多能经过的点的个数
题解
从右向左走反过来,就是说从左向右走,题目变成从最左两条不相交到达最右的路径,经过最多的点
一个问题是如何解决没有重复的点
这里的解决方案是
dp[i][j]
表示没有重复的点的情况下 一条路径走到点i,一条路径走到点j,经过的点的最大的个数
在状态转移的时候需要保证新的状态有i<j
,
dp[i][j] = dp[i][k]+1
,如果k->j
有路径, 我们保证了除了初始点dp[0][0]=1
以外,任何i不等于0,有dp[i][i] = 0
,
证明一下
首先任何可达的状态不会遗漏,假设存在路径 一边到i,一边到j,(不妨设i<j
)那么有它的来源一定能从[i][k]
来
再不重复点证明
抛开初始点
因为保证了i<j
,dp[i][j]
的来源仅为dp[i][k]
,我们有k一定不等于i,所以只要dp[i][k]
是没有重复点的即可
因此递归可证明,这样的dp是不会经过重复点,
最后考虑都到达最右的点,那么发现和dp[i][最右]
的 经过的点数一致,注意的是 注意判断点i到最右点是否有路径
#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
using namespace std;
const string filename = "tour";
void usefile(){
freopen((filename+".in").c_str(),"r",stdin);
freopen((filename+".out").c_str(),"w",stdout);
}
char s[210],t[210];
map<string,int>str2idx;
int n,m,mp[110][110],dp[110][110];
int main(){
usefile();
scanf("%d%d",&n,&m);
rep(i,0,n){
scanf("%s",s);
str2idx[s]=i;
}
rep(i,0,m){
scanf("%s %s",s,t);
mp[str2idx[s]][str2idx[t]]=1;
mp[str2idx[t]][str2idx[s]]=1;
}
int ans=1;
dp[0][0]=1;
rep(i,0,n){
rep(j,i+1,n){
rep(k,0,j){
if(mp[j][k]&&dp[i][k]&&dp[i][k]+1>dp[i][j]){
dp[i][j]=dp[j][i]=dp[i][k]+1;
}
}
}
if(mp[i][n-1]){
ans=max(ans,dp[i][n-1]);
}
}
printf("%d\n",ans);
}
Character Recognition
题目大意
先提供空格和26个小写字母的 字符画01矩阵,每个字符都是20*20
然后 你需要解析一段n*20
字符矩阵,n行20列
这段矩阵和标准的差异是,
- 对于一个字符,可能某一行被倍增了 变成21行,它紧接着倍增那行
- 对于一个字符,可能某一行被吞了 变成19行
- 0 和 1 和真实值不同
上面问题可以存在的组合有,和原始完全一致,单纯1,单纯2,1+3,2+3,其中 0和1 的改变率小于等于30%
题目呢,可以说相当于 USACO帮我们建了个OCR的模型!!!我们在该模型下实现算法
题解
f[i]表示从最开始到第i行最小误差
f[i] = min(f[i-19]+19行来匹配,f[i-20]+20行来匹配,f[i-21]+21行来匹配)
我们预先处理 所有字符的行(27*20
) 和 目标匹配的行N
O(N*27*20)
然后 直接dp,O(N*(20*3))
理论上如果做了前缀和后缀和优化
实现如下
#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
using namespace std;
const string filename = "charrec";
void usefile(){
freopen((filename+".in").c_str(),"r",stdin);
freopen((filename+".out").c_str(),"w",stdout);
}
int n,m;
char str[]=" abcdefghijklmnopqrstuvwxyz";
char s[30][30][30];// 标准字符集[idx][i][j]
char t[1210][30]; // 目标字符串[i][j]
int diff[30][30][1210]; // 预处理 [字符idx][字符的i行][目标的j行] = 01差异和
tuple<int,int,int>dp[1210]; // {最小代价,父节点,字符}
const int SUP = 1000000;
// 从st行开始匹配len行,返回{最小的代价,匹配的字符};
pair<int,int> solve(int st,int len){
pair<int,int>ret= {SUP,-1};
rep(i,0,27){
if(len==20){
int sum=0;
rep(k,0,20){
sum+=diff[i][k][st+k];
}
ret= min(ret,{sum,i});
}else{
// 这边重复计算了, 这里可以用前缀和 后缀和继续优化, 目测可以优化掉约10-20倍性能
// 不过因为USACO的数据比较小 这样已经是0.1s内了 就没写优化了
rep(j,0,20){ // 枚举删掉或增加的行
int p=st,sum=0;
rep(k,0,j){
sum+=diff[i][k][p++];
}
if(len==21){ // 19为删掉 21为增加
sum+=diff[i][j][p++];
sum+=diff[i][j][p++];
}
rep(k,j+1,20){
sum+=diff[i][k][p++];
}
ret= min(ret,{sum,i});
}
}
}
return ret;
}
int main() {
ios::sync_with_stdio(false);
freopen("font.in","r",stdin);
freopen("charrec.out","w",stdout);
scanf("%d",&n);
rep(idx,0,27){
rep(i,0,20){
scanf("%s",s[idx][i]);
}
}
fclose(stdin);
freopen("charrec.in","r",stdin);
scanf("%d",&m);
rep(i,0,m){
scanf("%s",t[i]);
dp[i] = {SUP,0,0};
}
// 预处理 把每个字符的每一行 都和 目标字符比
// 目标k行 和 第x个字符 的y行 比较不同的01个数
rep(idx,0,27){
rep(i,0,20){
rep(mm,0,m){
rep(j,0,20){
diff[idx][i][mm]+=s[idx][i][j]!=t[mm][j];
}
}
}
}
rep(i,18,m){
rep(len,19,22){
auto [cost,idx]=solve(i-len+1,len);
dp[i] = min(dp[i], {cost+(i-len<0?0:get<0>(dp[i-len])),i-len,idx});
}
}
vector<char>ans;
int i=m-1;
do{
ans.push_back(str[get<2>(dp[i])]);
}while((i=get<1>(dp[i]))>0);
per(itr,0,ans.size()){
printf("%c",ans[itr]);
}
printf("\n");
return 0;
}
Telecowmunication
题目大意
100点,无向图
网络流,最小字典序的最小割点
记得前不久才有一个USACO的 最大流问题
题解
老生常谈了,=。=难道是我练题的顺序不对,感觉在刚刚学完最大流 最小割的时候,就会学到拆点啊。
然后直接最小割点就出来了,然后字典序就依次枚举 再计算?想了想编码似乎不可行 1 + 100
vs 2+3
若都是可行的,显然前面的字典序小
#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
using namespace std;
const string filename = "telecow";
void usefile(){
freopen((filename+".in").c_str(),"r",stdin);
freopen((filename+".out").c_str(),"w",stdout);
}
int n,m,c1,c2;
int p2p[210][210];
int vis[210];
int flow[210][210];
void clearvis(){
rep(i,1,2*n+1){
vis[i]=false;
}
}
void dup(){
rep(i,1,2*n+1){
rep(j,1,2*n+1){
flow[i][j]=p2p[i][j];
}
}
}
int stk[210];
int bfs(int idx,int dst){
clearvis();
int st = 0,rear=0;
stk[rear++]=idx;
vis[idx] = true;
while(st<rear){
int p = stk[st];
rep(i,1,n*2+1){
if(vis[i])continue;
if(flow[p][i]){
if(i == dst){
return true;
}
stk[rear++]=i;
vis[i]=true;
}
}
st++;
}
return false;
}
int dfs(int idx,int dst){
if(idx == dst){
return 1;
}
vis[idx] = true;
rep(i,1,2*n+1){
if(vis[i])continue;
if(!flow[idx][i])continue;
int r = dfs(i,dst);
if(r){
flow[idx][i] -= r;
flow[i][idx] += r;
return r;
}
}
return 0;
}
int maxflow(){
int ret =0;
while(bfs(c1*2,c2*2-1)){
clearvis();
ret+=dfs(c1*2,c2*2-1);
}
return ret;
}
void addp(int p1,int p2){
int p1i=p1*2-1;
int p1o=p1*2;
int p2i=p2*2-1;
int p2o=p2*2;
if(p1!=c1 && p2 != c2){
p2p[p2o][p1i] = 1;
}
if(p1!=c2 && p2 != c1){
p2p[p1o][p2i] = 1;
}
}
int main(){
usefile();
cin>>n>>m>>c1>>c2;
rep(i,0,m){
int a,b;
scanf("%d %d",&a,&b);
addp(a,b);
}
rep(i,1,n+1){
p2p[i*2-1][i*2]=1;
}
dup();
int ans = maxflow();
cout<<ans<<endl;
vector<int>ps;
rep(i,1,n+1){
if(i== c1 || i==c2){
continue;
}
dup();
flow[i*2-1][i*2]=0;
int ret = maxflow();
if(ret == ans-1){
ps.push_back(i);
ans-=1;
p2p[i*2-1][i*2]=0;
}
}
rep(i,0,ps.size()){
printf("%d%c",ps[i]," \n"[i==ps.size()-1]);
}
return 0;
}
总结
第一题的DP的方法,我要是打cf没遇到,估计是想不出怎么处理路径不重复点 的 这样的状态转移
第二题的DP实现没啥好说的,但这样一个OCR模型 感觉也是很“实际”
第三题 emmmm 感觉刚学完网络流的时候 就知道拆点,好像没什么特别的。
USACO 5.4 章节的更多相关文章
- USACO 6.4 章节
The Primes 题目大意 5*5矩阵,给定左上角 要所有行,列,从左向右看对角线为质数,没有前导零,且这些质数数位和相等(题目给和) 按字典序输出所有方案... 题解 看上去就是个 无脑暴搜 题 ...
- USACO 6.3 章节 你对搜索和剪枝一无所知QAQ
emmm........很久很久以前 把6.2过了 所以emmmmmm 直接跳过 ,从6.1到6.3吧 Fence Rails 题目大意 N<=50个数A1,A2... 1023个数,每个数数值 ...
- USACO 5.5 章节
Picture 题目大意 IOI 1998 求n (<=5000)个矩形 覆盖的图形 的周长(包括洞), 坐标范围[-10000,10000] 题解 一眼离散化+2维线段树,但仔细一想 空间不太 ...
- USACO 5.3 章节
相关讲解可在USACO上看原文,也可以搜索nocow找到翻译的! (nocow上有些微翻译是有问题的,如果想看nocow翻译的建议也对着英文看) 以下记录以下 自己之前未掌握的一些要点,以及按自己的括 ...
- USACO 6.5 章节 世界上本没有龙 屠龙的人多了也便有了
All Latin Squares 题目大意 n x n矩阵(n=2->7) 第一行1 2 3 4 5 ..N 每行每列,1-N各出现一次,求总方案数 题解 n最大为7 显然打表 写了个先数值后 ...
- USACO 6.1 章节
Postal Vans 题目大意 4*n的网格,要经过所有点的有向有环,不重复经过点的路径总数 n<=1000 题解 显然 插头dp 以4为切面 问题是,会发现 超精度 解决呢要么实现高精度,要 ...
- (Step1-500题)UVaOJ+算法竞赛入门经典+挑战编程+USACO
http://www.cnblogs.com/sxiszero/p/3618737.html 下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年 ...
- 算法竞赛入门经典+挑战编程+USACO
下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发. 一.UVaOJ http://uva.onlinej ...
- USACO . Your Ride Is Here
Your Ride Is Here It is a well-known fact that behind every good comet is a UFO. These UFOs often co ...
随机推荐
- IDEA远程代码实时同步(可以自动实时同步)
前言 开发时一般的平台都是windows,但windows对开发极其不友好,一般都会在本地开启虚拟机,安装上linux环境进行项目的部署测试.下面介绍一种windows主机与linux虚拟机代码同步的 ...
- [NOIP2016PJ]魔法阵
今天模拟赛的题,,,唯一没有Giao出来的题(不然我就AKIOI了~) 最开始没想到数学题,把所有部分分都说一遍吧: 35分:纯暴力O(M^4)枚举,对于每一组a,b,c,d验证其是否合法. 60分: ...
- windows不重装系统和重建MBR分区表来扩展系统盘
step1. 下载Acronis Disk Director Suite工具,随便一搜都能下载的到. step2. 这个软件使用非常easy,网上有非常多图文教程.扩充盘使用Increase the ...
- Springboot-技术专区-war包部署在Tomcat上并修改默认端口
springboot项目内置Tomcat,直接打成jar包在dos下运行即可,但有时我们需要用war包以非内嵌Tomcat的方式来部署,以下是本人的实际经验 1.首先需要修改pom.xml文件 < ...
- JavaScript 各种遍历方式详解及总结
JavaScript 各种遍历方式详解 在$.each中想要终止循环,但是它没有continue或者break这样的终止方式,所以尝试使用return来进行终止,但是发现并没有跳出循环.为了搞清楚js ...
- 【问题解决方案】GitHub的md中使用库中图片
参考链接: 在GitHub中使用图片功能 步骤: 在github上的仓库建立一个存放图片的文件夹,文件夹名字随意.如:image 将需要在插入到文本中的图片,push到image文件夹中. 然后打开g ...
- 修改xampp中的MySQL密码
1.开启MySQL服务后,点击XAMPP Control Panel上的Admin按钮 2.依次点击"账户"--最后一个"修改权限"--修改密码 3.输入两次相 ...
- CSS中的关系选择器
关系选择器是指根据与其他元素的关系选择元素的选择器,常见的符号有空格.>.~,还 有+等,这些都是非常常用的选择器. 后代选择器:选择所有合乎规则的后代元素.空格连接. 相邻后代选择器:仅仅选择 ...
- Python人工智能识别文字内容(OCR)
环境准备 安装pytesseract和PIL 安装这两个包可以借助pip命令行安装 pip install PIL pip install pytesseract 安装识别引擎tesseract-oc ...
- 【抓包工具之Fiddler】增加IP列;session高亮
Fiddler 在处理每个session时,脚本文件CustomRules.js中的方法都会运行,该脚本使得你可以隐藏,标识或任意修改负责的session.规则脚本在运行状态下就可以修改并重新编译,不 ...