算法复习——区间dp

感觉对区间dp也不好说些什么直接照搬讲义了2333

例题:

1.引水入城(洛谷1514)

这道题先开始看不出来到底和区间dp有什么卵关系····

首先肯定是bfs暴力判一判可以覆盖到哪些城市····无解直接输出···有解得话就要想想了····

这道题关键是要发现··如果一个蓄水池所在城市可以覆盖到一些沙漠城市···那么这些沙漠城市肯定是一段····不然假设有一个城市是断开的而两边都被同一个蓄水池流出的水覆盖,这个城市四周的城市都肯定比它矮···(不理解举个反例吧···反正我举不出来)···然后就可以找到每一个蓄水池它对应的可以覆盖的区间···转化成一个关于线段覆盖的区间dp问题·····即可求解(dp方程看代码吧)

另外这道题bfs时注意是入队时打标记不然会爆···另外判条件时先判越界没有···

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1005;
const int gox[4]={1,0,-1,0};
const int goy[4]={0,1,0,-1};
struct node
{
  int x,y;
}que[N*N];
struct node1
{
  int l,r;
}g[N];
int map[N][N],n,m,tail,head,f[N];
bool visit[N][N];
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<‘0‘||c>‘9‘;c=getchar());
  for(;c<=‘9‘&&c>=‘0‘;c=getchar())
    f=(f<<3)+(f<<1)+c-‘0‘;
  return f;
}
inline void bfs()
{
  head=1,tail=0;
  for(int i=1;i<=m;i++)
  {
    que[++tail].x=1;que[tail].y=i;
    visit[que[head].x][que[head].y]=true;
  }
  for(;head<=tail;head++)
  {
    for(int i=0;i<=3;i++)
    {
      visit[que[head].x][que[head].y]=true;
      int vx=que[head].x+gox[i];int vy=que[head].y+goy[i];
      if(vx<1||vx>n||vy<1||vy>m||visit[vx][vy]||map[vx][vy]>=map[que[head].x][que[head].y])  continue;
      node temp;
      temp.x=vx,temp.y=vy;que[++tail]=temp;
      visit[temp.x][temp.y]=true;
    }
  }
}
inline void dfs(int x,int y,int u)
{
  visit[x][y]=true;
  if(x==n)
    g[u].l=min(g[u].l,y),g[u].r=max(g[u].r,y);
  for(int i=0;i<=3;i++)
  {
    int vx=x+gox[i];int vy=y+goy[i];
    if(visit[vx][vy]||vx<1||vx>n||vy<1||vy>m||map[vx][vy]>=map[x][y])  continue;
    dfs(vx,vy,u);
  }
}
int main()
{
  //("a.in","r",stdin);
  memset(f,inf,sizeof(f));
  n=R(),m=R();
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
      map[i][j]=R();
  bfs();
  int temp=0;
  for(int i=1;i<=m;i++)
    if(visit[n][i]==true)  temp++;
  if(temp!=m)
  {
    cout<<"0"<<endl;
    cout<<m-temp<<endl;
    return 0;
  }
  for(int i=1;i<=m;i++)
  {
    memset(visit,false,sizeof(visit));
    g[i].l=m+1;g[i].r=0;
    dfs(1,i,i);
  }
  f[0]=0;
  for(int i=1;i<=m;i++)
    for(int j=1;j<=m;j++)
      if(g[j].l<=i&&g[j].r>=i)
        f[i]=min(f[i],f[g[j].l-1]+1);
  cout<<"1"<<endl;
  cout<<f[m]<<endl;
  return 0;
} 
时间: 2025-01-02 07:49:07

算法复习——区间dp的相关文章

算法笔记--区间dp

1.石子归并问题 dp[i][j]表示区间i到j合并所需的最小花费. 先求出小区间的最小花费,再转移到大的区间. 转移方程:dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]) 初始状态:dp[i][i]=0 模板: for(int i=1;i<=n;i++)cin>>a[i],sum[i]=sum[i-1]+a[i] for(int l=2;l<=n;l++){ for(int i=1;i+l-1<=n;i++){ int j=i+l-1;

算法复习——背包dp

1.01背包 二维递推式子: 代码: for (i=1;i<=n;i++) for (x=m;x>=1;x--) if (x>=w[i]) f[i][x]=max(f[i-1][x-w[i]]+c[i],f[i-1][x]); else f[i][x]=f[i-1][x]; printf("%d",f[n][m]); // f(n,m)为最优解 return 0; 然而有时候,由于容量或者物品数过多可能导致用二维数组可能超空间,此时可以考虑一维的优化 用f[i]表示当

转载+删改:算法讲解之Dynamic Programing —— 区间DP [变形:环形DP]

发现一篇好文,可惜发现有一些地方有排版问题.于是改了一下,并加了一些自己的内容. 原文链接 对区间DP和其变式环形DP的总结. 首先先来例题. 石子归并 题目描述 Description 有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1].问安排怎样的合并顺序,能够使得总合并代价达到最小. 输入描述 Input Description 第一行一个整数n(n<=100) 第二行n个整数w1,w2...wn (wi

石子合并问题 (朴素区间DP&amp;&amp;GarsiaWachs算法)

题目链接: http://poj.org/problem?id=1738 给定n堆石头,每次只能合并相邻的两堆的石头,每次的话费是这两堆石头的和: 方法一: 区间DP  复杂度为O(n^3) 状态转移方程 dp[i][j]=min(dp[i][k]+dp[k+1][j]+sup[i][j]) dp[i][j]表示合并从i堆石头到第j堆石头的最小花费,sum[i][j]表示从第i堆到第j堆石头的和 代码如下: <span style="font-size:14px;">#in

区间DP与贪心算法的联系(uav Cutting Sticks &amp;&amp; poj Fence Repair(堆的手工实现))

因为,这两题有着似乎一样的解法所以将其放在一起总结比较,以达到更好的区分二者的区别所在. 一.区间DP uva的Cutting Sticks是一道典型的模板题. 题目描述: 有一根长度为l的木棍,木棍上面有m个切割点,每一次切割都要付出当前木棍长度的代价,问怎样切割有最小代价. 区间DP的定义: 区间动态规划问题一般都是考虑,对于每段区间,他们的最优值都是由几段更小区间的最优值得到,是分治思想的一种应用,将一个区间问题不断划分为更小的区间直至一个元素组成的区间,枚举他们的组合,求合并后的最优值.

区间DP与贪心算法的联系(uav Cutting Sticks &amp;&amp; poj Fence Repair)

因为,这两题有着似乎一样的解法所以将其放在一起总结比较,以达到更好的区分二者的区别所在. 一.区间DP uva的Cutting Sticks是一道典型的模板题. 题目描述: 有一根长度为l的木棍,木棍上面有m个切割点,每一次切割都要付出当前木棍长度的代价,问怎样切割有最小代价. 区间DP的定义: 区间动态规划问题一般都是考虑,对于每段区间,他们的最优值都是由几段更小区间的最优值得到,是分治思想的一种应用,将一个区间问题不断划分为更小的区间直至一个元素组成的区间,枚举他们的组合,求合并后的最优值.

CSUOJ-1980 不堪重负的数(区间dp)

1980: 不堪重负的树 Submit Page   Summary   Time Limit: 1 Sec     Memory Limit: 128 Mb     Submitted: 57     Solved: 20 Description 小X非常喜欢树,然后他生成了一个大森林给自己玩.玩着玩着,小X陷入了沉思. 一棵树由N个节点组成,编号为i的节点有一个价值Wi. 假设从树根出发前往第i个节点(可能是树根自己),一共需要经过Di个节点(包括起点和终点),那么这个节点对这棵树产生的负担

CSU 1616: Heaps(区间DP)

题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1616 1616: Heaps Time Limit: 2 Sec  Memory Limit: 128 MBSubmit: 48  Solved: 9[Submit][Status][Web Board] Description Zuosige always has bad luck. Recently, he is in hospital because of pneumonia.

LightOJ1044 Palindrome Partitioning(区间DP+线性DP)

问题问的是最少可以把一个字符串分成几段,使每段都是回文串. 一开始想直接区间DP,dp[i][j]表示子串[i,j]的答案,不过字符串长度1000,100W个状态,一个状态从多个状态转移来的,转移的时候要枚举,这样时间复杂度是不可行的. 然后我就想降维度了,只能线性DP,dp[i]表示子串[0,i]的答案.这样可以从i-1转移到i,str[i]单独作一段或者str[i]能和前面的组成回文串,方程如下: dp[i]=min(dp[i-1]+1,dp[j-1]+1) (子串[j,i]是回文串) 现在