<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      P2831 [NOIP 2016 提高組] 憤怒的小鳥 題解

      傳送門

      洛谷

      題目大意

      每關給你最多18只小豬(后文皆為18只),問你最少用幾條過原點拋物線全部干掉。
      注意這里 \(m\) 其實沒用,因為你要是會算最優(yōu)解了為啥還需要部分分啊?

      思路

      \(n\leq18\) ,不是暴搜就是狀壓。直接放棄暴搜。
      狀壓dp做法:

      1. 處理拋物線

      首先記錄這18只小豬所有可能產(chǎn)生的拋物線,如圖所示為例1的第一組樣例
      image
      注意這里“所有”可能產(chǎn)生的拋物線,包括只經(jīng)過一只小豬(* ̄(oo) ̄) 的拋物線。
      這個時候就有人會問,為了記錄拋物線,需要記錄 \(y=ax^2+bx\) 中的 \(a,b\) ,那要是記錄只經(jīng)過一只小豬的拋物線,還得考慮不經(jīng)過其他小豬,豈不是要算廢。
      其實解決方法很簡單,我們對于每條拋物線不記錄兩個存在誤差的浮點 \(a,b\) 而是直接用二進制下的18位整數(shù)狀壓這條拋物線經(jīng)過的小豬,可以證明對每只小豬一定存在只過它一點的拋物線。
      記錄只有一個點的拋物線很重要,我第一遍沒有搞,結(jié)果過了樣例,導致因為這個問題調(diào)了好久,有時還納悶這個dp有沒有真的考慮所有情況。

      然后就是考慮過多個小豬的拋物線。先枚舉第一只小豬,然后枚舉下標在第一只小豬之后的小豬。計算出過這兩只豬的拋物線,然后看其他小豬是否在此拋物線上,記錄在對應的拋物線數(shù)組里即可。
      代碼實現(xiàn):

      #include <bits/stdc++.h>
      using namespace std;
      typedef pair<double, double> pdd;
      const int N = 18, ZT = 1 << N;
      const double eps = 1e-6; // 處理浮點數(shù)相等的精度問題, 凡差小于epsilon即算相等
      int n, m;
      double x[N], y[N];
      int para[2000], cnt; // records parabolas
      
      // 計算過兩點的拋物線
      pdd calc(double x1, double y1, double x2, double y2)
      {
      	pdd res;
      	double &a = res.first, &b = res.second;
      	a = (x1 * y2 - x2 * y1) / (x1 * x2 * (x2 - x1));
      	b = (x2 * x2 * y1 - x1 * x1 * y2) / (x1 * x2 * (x2 - x1));
      	// printf("The parabola that goes through (%lf, %lf) and (%lf, %lf) is:\n\ty=%lfx^2+%lfx\n", x1, y1, x2, y2, a, b);
      	return res;
      }
      void solve()
      {
      	// pre-calculate the parabolas
      	for (int i = 0; i < n; ++i) {
      		para[cnt++] = (1 << i); // 只打小豬i的拋物線
      
      		int vst = 0;
      		for (int j = i + 1; j < n; ++j) {
      			if (vst & (1 << j)) continue;
      
      			// if (x[i] == x[j]) continue; // 防止calc函數(shù)出現(xiàn)除以0,但是好像不加也沒影響照樣AC
      
      			pdd tmp = calc(x[i], y[i], x[j], y[j]);
      			if (tmp.first >= 0) continue; // 題面要求拋物線開口向下,這不是數(shù)學,是物理!
      			para[cnt] = (1 << i);
      			for (int k = j; k < n; ++k) { // 這里k從j開始枚舉,或者直接para[cnt]|=(1<<j),然后這里j+1開始枚舉也沒問題
      				// printf("trying the parabola on (%lf, %lf): ", x[k], y[k]);
      				double res = tmp.first * x[k] * x[k] + tmp.second * x[k];
      				// printf("result is %lf\n", res);
      				if (abs(res - y[k]) <= eps) {
      					// printf("Success! It IS on the parabola!\n");
      					vst |= (1 << k); // 防止再次枚舉到過小豬 i,j,k的拋物線
      					para[cnt] |= (1 << k);
      				}
      			}
      			++cnt;
      		}
      	}
      	// for (int i = 0; i < cnt; ++i) {
      	// 	printf("parabola %d goes through these pigs: ", i);
      	// 	for (int j = 0; j < n; ++j) {
      	// 		if (para[i] & (1 << j)) {
      	// 			printf("%d ", j);
      	// 		}
      	// 	}
      	// 	printf("\n");
      	// }
      }
      

      注意拋物線數(shù)組開大點,不要以為拋物線最多只有18條,我們記錄的是每一條可能的拋物線。

      2. dp

      顯然對于每個狀態(tài) \(i(0\leq i\leq 2^{n+1}-1)\) ,枚舉每條拋物線 \(para_j\) 帶來的影響,有:

      \[\text{dp}[i|\text{para}_j]=\min(\text{dp}[i|\text{para}_j],\,\text{dp}[i]+1) \]

      至此,已成藝術完結(jié)撒花。

      代碼(含調(diào)試+原版注釋)

      #include <bits/stdc++.h>
      using namespace std;
      typedef pair<double, double> pdd;
      const int N = 18, ZT = 1 << N;
      const double eps = 1e-6;
      int n, m;
      double x[N], y[N];
      int para[2000], cnt; // records parabolas
      int dp[ZT];
      pdd calc(double x1, double y1, double x2, double y2)
      {
      	pdd res;
      	double &a = res.first, &b = res.second;
      	a = (x1 * y2 - x2 * y1) / (x1 * x2 * (x2 - x1));
      	b = (x2 * x2 * y1 - x1 * x1 * y2) / (x1 * x2 * (x2 - x1));
      	// printf("The parabola that goes through (%lf, %lf) and (%lf, %lf) is:\n\ty=%lfx^2+%lfx\n", x1, y1, x2, y2, a, b);
      	return res;
      }
      void solve()
      {
      	cnt = 0;
      	cin >> n >> m;
      	for (int i = 0; i < n; ++i) {
      		cin >> x[i] >> y[i];
      	}
      	// pre-calculate the parabolas
      	for (int i = 0; i < n; ++i) {
      		para[cnt++] = (1 << i); // 只打小豬i的拋物線
      		int vst = 0;
      		for (int j = i + 1; j < n; ++j) {
      			if (vst & (1 << j)) continue;
      			// if (x[i] == x[j]) continue;
      			// printf("pig %d and pig %d: ", i, j);
      			pdd tmp = calc(x[i], y[i], x[j], y[j]);
      			if (tmp.first >= 0) continue;
      			para[cnt] = (1 << i);
      			for (int k = j; k < n; ++k) {
      				// printf("trying the parabola on (%lf, %lf): ", x[k], y[k]);
      				double res = tmp.first * x[k] * x[k] + tmp.second * x[k];
      				// printf("result is %lf\n", res);
      				if (abs(res - y[k]) <= eps) {
      					// printf("Success! It IS on the parabola!\n");
      					vst |= (1 << k);
      					para[cnt] |= (1 << k);
      				}
      			}
      			++cnt;
      		}
      	}
      	// for (int i = 0; i < cnt; ++i) {
      	// 	printf("parabola %d goes through these pigs: ", i);
      	// 	for (int j = 0; j < n; ++j) {
      	// 		if (para[i] & (1 << j)) {
      	// 			printf("%d ", j);
      	// 		}
      	// 	}
      	// 	printf("\n");
      	// }
      	const int FULL = (1 << n) - 1;
      	for (int i = 1; i <= FULL; ++i) dp[i] = 30;
      	for (int i = 0; i <= FULL; ++i) {
      		for (int j = 0; j < cnt; ++j) {
      			dp[i | para[j]] = min(dp[i | para[j]], dp[i] + 1);
      		}
      	}
      	cout << dp[FULL] << '\n';
      }
      int main()
      {
      	// freopen("F.in", "r", stdin);
      	// freopen("F.out", "w", stdout);
      	ios::sync_with_stdio(false);
      	cin.tie(nullptr);
      	int T;
      	cin >> T;
      	for (int i = 1; i <= T; ++i) {
      		// printf("########### TEST CASE %d ###########\n", i);
      		solve();
      		// printf("\n");
      	}
      	return 0;
      }
      

      代碼(無//)

      #include <bits/stdc++.h>
      using namespace std;
      typedef pair<double, double> pdd;
      const int N = 18, ZT = 1 << N;
      const double eps = 1e-6;
      int n, m;
      double x[N], y[N];
      int para[2000], cnt;
      int dp[ZT];
      pdd calc(double x1, double y1, double x2, double y2)
      {
      	pdd res;
      	double &a = res.first, &b = res.second;
      	a = (x1 * y2 - x2 * y1) / (x1 * x2 * (x2 - x1));
      	b = (x2 * x2 * y1 - x1 * x1 * y2) / (x1 * x2 * (x2 - x1));
      	return res;
      }
      void solve()
      {
      	cnt = 0;
      	cin >> n >> m;
      	for (int i = 0; i < n; ++i) {
      		cin >> x[i] >> y[i];
      	}
      	for (int i = 0; i < n; ++i) {
      		para[cnt++] = (1 << i);
      		int vst = 0;
      		for (int j = i + 1; j < n; ++j) {
      			if (vst & (1 << j)) continue;
      			pdd tmp = calc(x[i], y[i], x[j], y[j]);
      			if (tmp.first >= 0) continue;
      			para[cnt] = (1 << i);
      			for (int k = j; k < n; ++k) {
      				double res = tmp.first * x[k] * x[k] + tmp.second * x[k];
      				if (abs(res - y[k]) <= eps) {
      					vst |= (1 << k);
      					para[cnt] |= (1 << k);
      				}
      			}
      			++cnt;
      		}
      	}
      	const int FULL = (1 << n) - 1;
      	for (int i = 1; i <= FULL; ++i) dp[i] = 30;
      	for (int i = 0; i <= FULL; ++i) {
      		for (int j = 0; j < cnt; ++j) {
      			dp[i | para[j]] = min(dp[i | para[j]], dp[i] + 1);
      		}
      	}
      	cout << dp[FULL] << '\n';
      }
      int main()
      {
      	ios::sync_with_stdio(false);
      	cin.tie(nullptr);
      	int T;
      	cin >> T;
      	for (int i = 1; i <= T; ++i) solve();
      	return 0;
      }
      

      別跑,還有壓行版

      #include<bits/stdc++.h>
      using namespace std;typedef pair<double,double>pdd;const int N=18,ZT=1<<N;const double eps=1e-6;int n,m;double x[N],y[N];int para[2000],cnt;int dp[ZT];pdd calc(double x1,double y1,double x2,double y2){pdd res;double&a=res.first,&b=res.second;a=(x1*y2-x2*y1)/(x1*x2*(x2-x1));b=(x2*x2*y1-x1*x1*y2)/(x1*x2*(x2-x1));return res;}void solve(){cnt=0;cin>>n>>m;for(int i=0;i<n;++i){cin>>x[i]>>y[i];}for(int i=0;i<n;++i){para[cnt++]=(1<<i);int vst=0;for(int j=i+1;j<n;++j){if(vst&(1<<j))continue;pdd tmp=calc(x[i],y[i],x[j],y[j]);if(tmp.first>=0)continue;para[cnt]=(1<<i);for(int k=j;k<n;++k){double res=tmp.first*x[k]*x[k]+tmp.second*x[k];if(abs(res-y[k])<=eps){vst|=(1<<k);para[cnt]|=(1<<k);}}++cnt;}}const int FULL=(1<<n)-1;for(int i=1;i<=FULL;++i)dp[i]=30;for(int i=0;i<=FULL;++i){for(int j=0;j<cnt;++j){dp[i|para[j]]=min(dp[i|para[j]],dp[i]+1);}}cout<<dp[FULL]<<'\n';}int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin>>T;for(int i=1;i<=T;++i)solve();return 0;}
      

      總結(jié)

      挺容易寫的一道藍題,沒調(diào)太久。
      算是自己想不出,一聽到枚舉拋物線就懂的題。

      posted @ 2025-10-06 11:10  peter_code  閱讀(4)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 鲁丝一区二区三区免费| 麻豆精品传媒一二三区| 亚洲免费一区二区av| 亚洲人成网站在线播放2019| 西西444www高清大胆| 久久久国产乱子伦精品作者| 色综合天天综合网天天看片| 白嫩少妇无套内谢视频| 亚洲avav天堂av在线网爱情| 欧美丰满熟妇乱XXXXX网站| 白白色发布永久免费观看视频| 欧美国产亚洲日韩在线二区 | 国产欧美日韩亚洲一区二区三区| 一本一道av无码中文字幕麻豆| 日本一区二区三区在线 |观看| 日韩无套无码精品| 国产自产一区二区三区视频| 国产在线永久视频| 国产精品会所一区二区三区| 九九在线精品国产| 福利在线视频一区二区| 日本在线 | 中文| 亚洲一区二区经典在线播放| 国产一区二区av天堂热| 国内精品久久久久精免费| 日韩精品国内国产一区二| 亚洲日本精品一区二区| 国产老熟女狂叫对白| 亚洲av精选一区二区| 伊人久久综合无码成人网| 国产性天天综合网| 中文字幕乱码在线播放| 乱码中文字幕| 国产精品香蕉在线观看不卡| 午夜一区二区三区视频| 欧美大胆老熟妇乱子伦视频| 18禁无遮挡啪啪无码网站破解版| av中文字幕国产精品| 久热在线中文字幕色999舞| 无码人妻斩一区二区三区| 国语自产精品视频在线看|