1. 程式人生 > >NOIP 2016 Day2 T3 憤怒的小鳥

NOIP 2016 Day2 T3 憤怒的小鳥

沒有人知道我A掉這道題時

是多麼激動和沮喪

激動是因為終於自己一次性A了第一道noip2016的題

沮喪是因為我竟然將半個小時的時間近乎崩潰的尋找狀態壓縮的方程錯誤,而問題居然是出在double精度處理上(F**k U double)!!!

先講一講思路

由題意得

條件1、豬的個數小於18個。

條件2、鳥的個數無窮大。

條件3、鳥必須從(0,0)打出,並且拋物線a*x^2+b*x的a必須嚴格小於0;

問題1、我們需要求得最少用打完所有豬的鳥是多少隻。

若要求打完所有豬豬需要用的鳥的個數,我們需要用打完某一部分豬豬後所用的鳥的最小值去更新打完所有豬豬所用的鳥的最小數量,於是我們很容易將這個問題轉化為多個子問題的最優解,可以理解嗎?

那麼顯然這是一道動態規劃的題。

但是接下來如何轉移方程呢?

這個難倒了我們。

難點1、

由於每一條經過某兩個豬豬可以確定一條拋物線,但其所經過的其他豬豬的數量是不知道的。

腦洞大開——

不對,既然豬豬的數量這麼少,我們可否將豬豬被打死了或者沒有被打死構成一個0101010……的長度為n的狀態,進行狀壓

定義狀態

在“狀態01串”上的在i位置上的“1”表示當前狀態按照輸入順序的第i只豬豬已經被打死了;

在“狀態01串”上的在i位置上的“0”表示當前狀態按照輸入順序的第i只豬豬仍未被打死;

每一個狀態是什麼情況,哪些豬豬已經被打死了是沒有被打死一目瞭然,於是我們可以去列舉狀態。

定義dp陣列

dp[ i ]為一維陣列;

下標 i 表示打小鳥打到 i 這個狀態所使用的鳥的最小值是dp[ i ]。

解決難點1

我們可以對每兩個豬豬確定的一條拋物線解析式的a和b計算出來。接著列舉所有的豬豬,如果可以被打的話也加入到打掉這兩個豬豬所牽連的其他豬豬的集合之中!存入陣列g[ id1 ][ id2 ],表示打死編號為id1以及id2的豬豬的拋物線一起打死的(被牽連的)豬豬狀態。

注意,這個狀態無論上一層是什麼狀態,只要使用了這條拋物線,對於被牽連的豬豬的狀態一定是1!

我們怎麼對這個狀態打新的並且還沒有死的豬豬呢?

這裡用到了位運算子:| (或)。

優點

1|1=1

1|0=1

0|1=1

0|0=0

無論id1與1d2兩頭豬豬所確定的拋物線所經過的每一頭豬豬有沒有被打死,總之沒有被打死的(“0”)“或”上加上拋物線不會被打死的(“0”),還是不會被打死。其他情況根據上面的等式推導,一定成立,可以感性理解或者推一下,不再贅述。

得解

所以可以列舉代表當前狀態01串的十進位制數,被打的第一頭將被打死的目標傻豬豬id1和第二頭將被一起打死的目標傻豬豬id2;

在當前狀態打一隻小鳥:dp[ s | g[ i ][ j ] ];

加上費用,每次為+1;

注意但有可能這條拋物線對當前狀態一點貢獻都沒有,也就是其經過的所有豬豬都早就被更優的方案:dp[ s | g[ i ][ j ] ]打死了。那我乾脆就不打了,所以要兩者取min值。

得到狀態轉移方程:

dp[ s ] = min( dp[ s | g[ i ][ j ] ] , dp[ s ]+1 );

還有一點小瑕疵

對於double來說,求出某一條拋物線的我們,判斷其他豬豬是否會被該拋物線射到時,一定不能單純用“==”去判斷ax^2+bx是否與y相等,而是要用ax^2+bx-y<1e-6!天哪,就是這個,我排了半個小時的dp雷,結果一無所獲。上了個廁所才發現,我的天,是不是精度的問題!!!

改了就AC了,真是神奇的double。

以後一定要注意啊!!!

貼上程式碼

比較醜,別嫌棄……

而且被某胡姓老師給帶壞了定義變數是時變數的名字 —— 全用中文拼音……

#include<bits/stdc++.h>

const int N=100000+5;

using namespace std;

int dp[1<<20],g[20][20],n,m,T;
double x[N],y[N],a,b;

inline void readdb( double&x ) {
    double f=1;x=0;char c=getchar();
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=10*x+c-48,c=getchar();
    x=x*f;
}

int yu_chu_li(double aa,double bb,double cc,double aaa,double bbb,double ccc){
	int er_jin_zhi=0;
	b=(cc-ccc*aa/aaa)/(bb-bbb*aa/aaa);
	a=(cc-ccc*bb/bbb)/(aa-aaa*bb/bbb);
	if(a>=0 || aa==aaa ) return 0;
	for(int k=1;k<=n;k++)
	    if(abs(x[k]*x[k]*a+x[k]*b-y[k])<1e-6)
		    er_jin_zhi+=(1<<(k-1));
	return er_jin_zhi;
}

int main(){
	scanf("%d",&T);
	for(int t=1;t<=T;t++){
		memset(dp,0x7f,sizeof(dp));
		memset(g,0,sizeof(g));
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
			scanf("%lf%lf",&x[i],&y[i]);
		for(int i=1;i<=n;i++)
		    for(int j=1;j<=n;j++)
		        g[i][j]=yu_chu_li(x[i]*x[i],x[i],y[i],x[j]*x[j],x[j],y[j]);
		dp[0]=0;
		for(int i=1;i<=n;i++)
		    g[i][i]=(1<<(i-1));
		for(int i=1;i<=n;i++)
		    for(int j=1;j<=n;j++)
		        for(int s=0;s<(1<<n);s++)
		            dp[s|g[i][j]]=min(dp[s|g[i][j]],dp[s]+1);
		printf("%d\n",dp[(1<<n)-1]);
	}
	
	return 0;
} 

繼續努力!!

相關推薦

NOIP 2016 Day2 T3 憤怒小鳥

沒有人知道我A掉這道題時是多麼激動和沮喪激動是因為終於自己一次性A了第一道noip2016的題沮喪是因為我竟然將半個小時的時間近乎崩潰的尋找狀態壓縮的方程錯誤,而問題居然是出在double精度處理上(F**k U double)!!!先講一講思路由題意得條件1、豬的個數小於1

BZOJ 4326 NOIP 2015 DAY2 T3 淺談二分及樹上差分陣列DFS動態統計

世界真的很大 今天正值全校運動會然而卻被困機房 想著寫完這道題就下樓看運動會於是乎一A,老天luogu的“大凶”能奈我何? 於是還剩一點時間,所以寫一下部落格 看題先: description: 公元 2044 年,人類進入了宇宙紀元。L

NOIP 2016 Day2 解題報告

NOIP 2016 Day2 解題報告 by 毒液哥 Problem 100Points 注意到n, m <= 2000. 而我們的問題是對範圍內所有組合數統計能被k整除的個數,所以我們需要得到範圍內所有的組合數模k的餘數。 要注意j <=

NOIP 2016 PJ T3 海港

P2058 海港 題目描述 小K是一個海港的海關工作人員,每天都有許多船隻到達海港,船上通常有很多來自不同國家的乘客。 小K對這些到達海港的船隻非常感興趣,他按照時間記錄下了到達海港的每一艘船隻情況;對於第i艘到達的船,他記錄了這艘船到達的時間ti (單位:秒),船上的

NOIP 2016 提高組 Day2 憤怒小鳥

http://blog.csdn.net/u011056504/article/details/53367538 原理我懂了 注意到資料範圍:N<=18  有什麼演算法?  暴力?狀壓!  狀壓DP,對於每隻豬1和0表示是否被打掉了  設f[s]為當前狀態的最小

Noip 2016 憤怒小鳥 題解

開始 題目 觀察 div 都在 memset str 例如 space        [NOIP2016]憤怒的小鳥                  時間限制:1 s 內存限制:256 MB 【題目描述】 Kiana最近沈迷於一款神奇的遊戲無法自拔。 簡單來

狀壓dp NOIP 2016 憤怒小鳥

題意:有 n n n只豬,第

NOIP 2016 提高組】憤怒小鳥

DH ---------以上初三THU/PKU大爺---- Alan_cty LYD XHM HZJ ZZ ---以下是大神%-- YMW Samjia2000 werkeytom_ftd Crazy_czy WorldWide_D Yxuan

noip 2016(憤怒小鳥)(狀壓dp)

狀壓dp,每位代表一隻豬,1為豬打到了,0為豬還沒打到 兩個豬的座標確定一條拋弧線(即為打出鳥的軌跡) g[i][j]表示由i豬和j豬確定的拋弧線,能打到的豬。(是一個二進位制的狀態) 預處理:把能被i豬和j豬確定的這條拋弧線能打到的豬都用狀壓的1來表示,存到g[i][

【NOIP2016提高組day2憤怒小鳥

span math cst clas 解析式 ++ amp -- memset 分析 Kiana最近沈迷於一款神奇的遊戲無法自拔。 簡單來說,這款遊戲是在一個平面上進行的。 有一架彈弓位於 (0, 0) 處,每次Kiana可以用它向第一象限發射一只紅色的小鳥, 小鳥們的飛行

【狀壓DP】【NOIP提高組】憤怒小鳥

這是道不算水的狀壓DP 這道題對我的吸引力很大,為什麼呢,因為它的背景是遊戲啊 題目描述 Kiana 最近沉迷於一款神奇的遊戲無法自拔。 簡單來說,這款遊戲是在一個平面上進行的。 有一架彈弓位於 (0,0)(0,0) 處,每次 Kiana 可以用它向第一象限發射

憤怒小鳥

logs ava cnblogs .... 表示 pan col sca div X星球憤怒的小鳥喜歡撞火車! 一根平直的鐵軌上兩火車間相距 1000 米兩火車 (不妨稱A和B) 以時速 10米/秒 相對行駛。 憤怒的小鳥從A車出發,時速50米/秒,撞向B車,然後返回去撞A

模擬(玩具謎題NOIP 2016 提高組 Day 1 第一題vijos2003)

順時針 std 字符 true cnblogs 中一 else point 整數和 描述 小南有一套可愛的玩具小人,它們各有不同的職業。 有一天,這些玩具小人把小南的眼鏡藏了起來。小南發現玩具小人們圍成了一個圈,它們有的面朝圈內,有的面朝圈外。如下圖: 這時sin

noip 2016】普及組

scrip one clu sel b+ -s 位置 ref print T1.買鉛筆 題目鏈接 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4

Noip 2013 Day2 T1 積木大賽(block)

ace int 所有 沒有 lock 補充 efi cnblogs names Noip 2013 Day2 T1 積木大賽(block) 【題目描述】 春春幼兒園舉辦了一年一度的“積木大賽”。今年比賽的內容是搭建一座寬度為的大廈,大廈可以看成由

NOIP 2016 普及組Solution

ace solution int () pri clas include col view 第一題 直接貼Code: 1 #include <cstdio> 2 int min(int a,int b) 3 { 4 return a<b

NOIP 2015 DAY2

描述 efi include 工作 edge 包含 影響 con 數據 跳石頭 題目背景 一年一度的“跳石頭”比賽又要開始了! 題目描述 這項比賽將在一條筆直的河道中進行,河道中分布著一些巨大巖石。組委會已經選擇好了兩塊巖石作為比賽起

2012Noip提高組Day2 T3 疫情控制

std name head printf fin 一個空格 pre 控制 不同 題目描述 H 國有 n 個城市,這 n 個城市用 n-1 條雙向道路相互連通構成一棵樹,1 號城市是首都,也是樹中的根節點。 H 國的首都爆發了一種危害性極高的傳染病。當局為了控制疫情,不讓

Noip 2016 天天愛跑步 題解

最短路 oid 數量 mes stream 編號 個人 str fin     [NOIP2016]天天愛跑步           時間限制:2 s 內存限制:512 MB 【題目描述】 小C同學認為跑步非常有趣,於是決定制作一款叫做《天天愛跑步》的遊戲。《天天愛跑

[NOIp 2016]換教室

log clu 誤差 border vertical sam borde hint str Description 對於剛上大學的牛牛來說,他面臨的第一個問題是如何根據實際情況申請合適的課程。 在可以選擇的課程中,有 $2n$ 節課程安排在 $n$ 個時間段上。在第 $