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 ...
随机推荐
- Ecshop 商品详情页如何添加立即购买按钮
1,加到位置 <li class="add_cart_li"> <a href="javascript:addToCart1({$goods.goods ...
- 如何为自己的网站添加HTTPS服务
如何为自己的网站添加HTTPS服务,针对单个域名而言的,下面介绍网站添加https方法,拿阿里云方法 1.准备证书文件 进入阿里云管理控制台-安全-证书服务点击购买证书服务,进入证书购买页面(放心,我 ...
- 并行开发 2.plink
原文:8天玩转并行开发——第二天 Task的使用 在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击, ...
- 踩坑,vue项目中,main.js引入scss文件时报错
当我们在src目录下创建.scss文件,并在main.js中引用,运行时会报: ERROR Failed to compile with 1 errors 5:25:07 PMThis relativ ...
- 阿里云服务器安装mongodb
1.下载mongodb curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.2.9.tgz 2.解压 tar zxvf mo ...
- tensorflow创建cnn网络进行中文手写文字识别
数据集下载地址:http://www.nlpr.ia.ac.cn/databases/handwriting/download.html chinese_write_detection.py # -* ...
- Introduction to Sound Programming with ALSA
ALSA stands for the Advanced Linux Sound Architecture. It consists of a set of kernel drivers, an ap ...
- hdu1231 最长连续子序列和
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1231 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, N ...
- PL SQL安装
首先,在官网下载PL SQL 的对应版本,本机是64位的就下载64位的,网址:https://www.allroundautomations.com/downloads.html#PLS 点击应用程序 ...
- 输出匹配项:grep
命令格式: grep pattern [file...] When grep encounters a "pattern" in the file, it prints out t ...