算法竞赛经典例题

村庄债务问题

有一个村庄,村里有n户人家,他们整整齐齐地排成一列,编号从左向右依次是1~n

他们当中,有的欠别人钱,有的则被别人欠钱。今天,村委会决定统一处理这些债务。

然而这个村庄有一个神奇的特性,钱只能在相邻的人家之间流动,也就是说对于第i户,他的钱只能给第i-1户或第i+1户

如果1欠了3的钱,则必须先把钱给2,再由2给3

现在村委会想知道,他们至少需要多少次付钱的操作才能把所有债务问题解决。

输入

第一行,一个整数n

第二行n个整数,第i个数v[i]代表第i户人家的债务情况。正代表欠钱,负数代表被欠钱。

n<=1e5

v[i]<=1e9

输出 一个整数 表示最少的流动量

样例

输入

5

3 0 0 0 -3

输出

12

解释

1给2   3块钱 流动量+=3

2给3   3块钱 流动量+=3

3给4   3块钱 流动量+=3

4给5   3块钱 流动量+=3

流动量=12

这道题实际上是在说,经过若干次操作,一个东西由一个状态变成另外一个状态。而最终状态比较特殊,要求所有人既不欠钱,也不被欠钱。

也就是说所有v[i]都等于0

所有......v[i]......?有点麻烦,不如换个思路想想,v[i]=0对于任意i∈[1,n]均成立,那么对于i=1肯定成立

为什么要这么想呢,因为1的特殊位置,他只能和2发生关系,无论欠钱还是被欠钱,都只能通过2和别人交换。

但是对于2~n-1来说,他的左邻右舍都可以和他进行交换,问题会比较复杂。

所以我们先从最边上的1号入手

那么就不难想到一个算法

ans=0

for i=1 To n-1

  ans+=abs(v[i])    //abs表示绝对值

  v[i+1]+=v[i]

  v[i]=0

print(ans)

翻转游戏(洛谷P1764)

就不写题面了,直接贴传送门(其实就是我懒得打了)

https://www.luogu.com.cn/problem/P1764

为了方便讨论,定义f(i,j)操作为:

  翻转第i行第j列的棋子

  翻转(i,j)上下左右的四个棋子

定义操作F(S)为:

  对于所有(i,j)∈S

    f(i,j)

可以想到一个O(2n*n)算法

枚举全体棋子的子集S对S中所有棋子进行f操作。操作完检查是否为同一种颜色

不过这个算法严重超时,一个世纪都跑不完(不排除一个世纪以内出现可以快速跑完这个算法的计算机)

不要被他的[提高+/省选-]的难度吓到,其实思路和刚才的题一样

所有的棋子都变成一种颜色,哪就先考虑全变成黑色,讨论出全是黑色的算法,那么白色同理

全是黑色,就意味着第一排的所有棋子都是黑色

为什么这么想呢?因为想要影响第一行,只有在第一行操作也就是f(1,1),f(1,2),f(1,3)...f(1,n)和在第二行操作,即f(2,1),f(2,2),f(2,3)...f(2,n)只有两行

然而对于第i行(i∈[2,n-1])能影响它的是第i-1行的操作,第i行的操作,第i+1行的操作,共三行

是不是像极了上一题?

这样就可以优化一下那个一个世纪都跑不完的算法了

原算法枚举了所有棋子的子集,我们可以枚举第一行棋子的子集S1

做一次F(S1)

等等,这样下来第一行很有可能是乱七八糟的啊

不要急,刚才说了,第一行可以被第一行和第二行的f操作影响,进行完F(S1)后,我们就不再直接操作第一行了

那么想把第一行全部变成黑色,只能通过操作第二行影响第一行

并且由于不再操作第一行了,那么想让第一行达到全黑,就可以确定唯一的第二行的子集S2使得F(S2)过后,第一行是全黑

F(S2)过后,第一行全黑,第二行很有可能是乱七八糟的,但这时候已经不能操作第一行和第二行了,只能通过操作第三行影响第二行

于是就可以确定唯一的第三行子集S3使得F(S3)过后,第二行是全黑

以此类推,可以由S1确定S2~Sn

在进行完Sn以后,1~n-1一定是全黑的,虽然第n行很可能是乱七八糟的,但  如果存在解,那么一定能枚举到一个S1使得第n行在操作完以后是全黑的

如果找不到,那么无解

伪代码如下

ans=+∞;

for S1⊆第一行:

  F(S1)

  temp=|S1|          //|S1|表示S1的元素个数

  for i=2 to n

    for j= 1 to n

      if (i-1,j)是白色:

        f(i,j)

        temp++

  if 第n行全黑

    ans=min(ans,temp)

if (ans<+∞) print(ans)

else print("Impossible")

原文地址:https://www.cnblogs.com/LMXZ/p/12072483.html

时间: 2024-08-29 12:26:21

算法竞赛经典例题的相关文章

《算法竞赛经典入门完整版》习题

习题2-3 韩信点兵 #include<stdio.h>#include<time.h>int main(){    int a,b,c,S = 10;    scanf("%d",&a);    scanf("%d",&b);    scanf("%d",&c);    while(!(S%3 == a && S%5 == b && S%7 == c &&a

《算法竞赛入门经典(第二版)》pdf

下载地址:网盘下载 内容简介  · · · · · · <算法竞赛入门经典(第2版)>是一本算法竞赛的入门与提高教材,把C/C++语言.算法和解题有机地结合在一起,淡化理论,注重学习方法和实践技巧.全书内容分为12 章,包括程序设计入门.循环结构程序设计.数组和字符串.函数和递归.C++与STL入门.数据结构基础.暴力求解法.高效算法设计.动态规划初步.数学概念与方法.图论模型与算法.高级专题等内容,覆盖了算法竞赛入门和提高所需的主要知识点,并含有大量例题和习题.书中的代码规范.简洁.易懂,不

《算法竞赛入门经典》动态规划复习

codevs 4979 数塔 1 #define N 100 2 #include<iostream> 3 using namespace std; 4 #include<cstdio> 5 int a[N][N],b[N][N],n; 6 int main() 7 { 8 scanf("%d",&n); 9 for(int i=1;i<=n;++i) 10 for(int j=1;j<=i;++j) 11 { 12 scanf("

《算法竞赛入门经典第二版》 P35 习题2-4 子序列的和(subsequence)

/* <算法竞赛入门经典第二版> P35 习题2-4: 输入两个正整数 n < m < 10^6,输出 (1/n)^2 + 1/(n+1)^2 +……+ 1/m^2,保留5位小数. 输入包含多组数据,结束标志为 m=n=0. 有错欢迎指出^_^ */ #include<stdio.h> int main() { int m,n,i,j=1; while(scanf("%d%d",&m,&n) != EOF) { double sum

算法竞赛_入门经典_刘汝佳__(2)

1,有几位数字 #include<stdio.h> int main_2_1_digit(){ int n; while(scanf("%d",&n)){ int count = 0; if(n==0) count = 1; while(n){ count++; n/=10; } printf("%d\n",count); } return 0; } 2,三位数的三个数字 #include<stdio.h> int main_2_2_

算法竞赛入门经典_4.3_递归

看代码 #include <stdio.h> int f(int n){ return n == 0?1:f(n-1)*n; } int main() { printf("%d\n", f(5)); return 0; } 上面f函数使用了递归,递归由两部分组成,一是递归头,二是递归体. 我们使用gcc调试工具 H:\编程书籍学习\算法竞赛入门经典2代码\算法入门经典第四章>b f 'b' 不是内部或外部命令,也不是可运行的程序 或批处理文件. H:\编程书籍学习\算

算法竞赛入门经典训练指南

最近在看算法竞赛入门经典训练指南这本书,书中不错的算法我将在博客中发布,和大家共同学习. 题目: 在你的王国里有一条n个头的恶龙,你希望雇一些骑士把它杀死(即砍掉所有头).村里有m个骑士可以雇佣,一个能力值为m的骑士可以砍掉一个直径不超过x的头,且需要支付x个金币.如何雇佣骑士才能砍掉恶龙的所有头,且需要支付的金币最少?注意,一个骑士只能砍一个头(且不能被雇佣两次). 输入格式: 输入包含多组数据.每组数据的第一行为正整数m和n(1<=m,n<=20 000):以下m行每行为一个整数,即恶龙每

算法入门经典第六章 例题6-14 Abbott的复仇(Abbott&#39;s Revenge)BFS算法实现

Sample Input 3 1 N 3 3 1 1 WL NR * 1 2 WLF NR ER * 1 3 NL ER * 2 1 SL WR NF * 2 2 SL WF ELF * 2 3 SFR EL * 0 Sample Output (3,1) (2,1) (1,1) (1,2) (2,2) (2,3) (1,3) (1,2) (1,1) (2,1) (2,2) (1,2) (1,3) (2,3) (3,3) 析 题目的大意是,输入起点,离开起点时的朝向和终点,求一条最短路. 每一个

算法竞赛入门经典-训练指南(10881-Piotr&#39;s Ants)

题目大意: 一根长度为L的木棍一堆蚂蚁爬,向左或向右,速度都为1,若两蚂蚁碰撞则同时转头(转身时间忽略不计),问T时间之后每只蚂蚁的位置: 输入:t,(t个样例),每个样例输入 L,T,n,接下来是n行每行两个数据,一个POS(位置),一个dir(方向): 输出:按输入顺序输出每只蚂蚁的最终位置,若处于碰撞状态则输出Turning,掉下去输出"Fell off": 解题思路: 本题类似于<挑战程序设计>的一道水题(POJ -1852  Ants),思路题:不过本题输入并不一