問題描述
小q正在設計一種棋類遊戲。在小q設計的遊戲中,棋子可以放在棋盤上的格點中。某些格點之間有連線,棋子只能》 在有連線的格點之間移動。整個棋盤上共有v個格點,編號為0,1,2…,v-1,它們是連通的,也就是說棋子從任意格》 點出發,總能到達所有的格點。小q在設計棋盤時,還保證棋子從乙個格點移動到另外任一格點的路徑是唯一的。輸入格式小q現在想知道,當棋子從格點0出發,移動n步最多能經過多少格點。格點可以重複經過多次,但不重複計數。
第一行包含2個正整數v,n,其中v表示格點總數,n表示移動步數。輸出格式接下來v-1行,每行兩個數ai,bi,表示編號為ai,bi的兩個格點之間有連線。 v,n≤ 100, 0 ≤ ai,bi < v
輸出一行乙個整數,表示最多經過的格點數量。樣例輸入
5 2樣例輸出 t1的位置,果然是道水題。1 0
2 1
3 2
4 3
從題目描述中看出這是一棵樹。那麼顯然就是一道樹形dp。
狀態也很顯然:
以0號節點為根, f[i][j][0]表示在i號節點所在的子樹走j步且最後回到i號節點經過的最大點數。那麼狀態轉移方程:f[i][j][1]表示在i號節點所在的子樹走j步且最後不回到i號節點經過的最大點數。
設y為p的兒子,則:
f[p][j][1]=max (1<=k<=j)注意討論時按照揹包動規的思想,從大到小列舉j。另注意f陣列初值均為1。f[p][j][1]=max (2<=k<=j)
//區別上乙個方程,走到兒子再走回來要兩步
f[p][j][0]=max (2<=k<=j)
#include
#define maxn 105
#define maxm 205
#define max(x,y) ((x>y)?(x):(y))
using
namespace
std;
int f[maxn][maxn][2],v,n;
//0 回來 1 不回來
int tot,en[maxm],las[maxn],nex[maxm];
void add(int x,int y)
void dp(int p,int fa)
}}int main()
看了這篇才知道還有這種操作@greatzccy
但是我覺得不是很像貪心= =,畢竟沒看出來貪心的明顯特徵。反正不管是不是總之我還是太菜了就對了。
還是簡要概括一下思路:
首先如果從0出發的最長鏈長度小於n,答案顯然是n+1。
除此之外,如果一種走法可能是最優解,那麼它必須滿足這樣的條件:
在某一條鏈上的邊只走了一次,在鏈周圍的一些邊上走了兩次。(不考慮n大到把樹走完都還有剩餘的情形,這種情形在最後判斷一下即可)
設鏈長為len,那麼答案就是(n-len)/2+len+1。
從一次函式的觀點看,最優解應當是在len取最大時,即從0出發的最長鏈的長度。(0號點顯然在「那條鏈」上)
#include
#define maxn 105
#define maxm 205
#define min(x,y) ((x#define max(x,y) ((x>y)?(x):(y))
int n,v,len;
int tot,en[maxm],las[maxn],nex[maxm];
void add(int
x,int
y)void dfs(int p,int f,int dis)
len=max(len,dis);
}int main()
CQOI2017 小Q的棋盤
看到這道題,很容易想到是一道樹型dp,那麼該如何做?首先我們可以先這樣定義狀態,fi,jf fi,j 表示以i ii為根節點,向下走j jj步最多能經過多少點,但很明顯,只是這樣是不行的,所以我們再加一維,第三維為0表示不會到根節點,第三維為1表示需要回到根節點,那麼就可以得出狀態轉移方程 f ma...
CQOI2017 小Q的棋盤
給定一棵樹,點數為n,從根節點出發,每一步可以走向與當前點有直接邊相連的點,問走m步最多能經過多少個點。邊和點均可以重複經過,但不重複計數。f p j 表示從 p 出發走向以 p 為根的子樹,一共走 k 步並且最終回到 p 最多能經過的點數。g p j 表示從 p 出發走向以 p 為根的子樹,一共走...
CQOI2017 老C的方塊
傳送門 nkoj4042 這是一道網路流題。我在這道題上耗了很久 感謝 oblack幫我修改 這道題的思維上的難度並不大。以下是我的想法 首先要確定乙個大的方向,題目中要求移除一些方塊使得剩餘方塊無法構成 討厭的形狀 很容易就想到了最小割。仔細觀察一下,可以發現這些討厭的形狀是由兩個方格 一條特殊的...