日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

18寒假最后一测+dijistra模板

發布時間:2023/12/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 18寒假最后一测+dijistra模板 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目名稱

run

homework

cut

輸入

run.in

homework.in

cut.in

輸出

run.out

homework.out

cut.out

每個測試點時限

1秒

1秒

2秒

內存限制

64MB

64MB

64MB

測試點數目

10

10

10

每個測試點分值

10

10

10

是否有部分分

題目類型

傳統

傳統

傳統

?

run

Background:

??? ??? 穿過時空隧道,小明來到了秦朝。我是誰?我在哪?

????? ????? “哈哈哈,金科,發什么呆呢,你的刺殺已經失敗了!”秦王躲在柱子后狂妄的笑。

????? ????? 一股熱血在小明體內流動,他竟情不自禁地追了上去。

Description:

??? ??? 宮殿里一共有n根柱子,假設柱子在二維平面內的位置為(xi,yi)。金科現在在一號柱子,秦王現在在n號柱子。金科(小明)會飛檐走壁所以他從i號柱子到j號柱子的距離為min(|xi-xj|,|yi-yj|)。深知自己并不能刺殺秦王,所以小明知道事實上自己竭盡全力,也離秦王有一步之遙,所以小明想知道自己到達n號柱子的最短距離-1是多少,因為這將是他人生能走過的最后的路。

Input:

??? ??? 第一行一個數n。

????? ????? 接下來n-1行每行兩個數x,y分別表示xi和yi。

Output:

????? ????? 一行一個數表示從1號柱子走到n號柱子的最短距離減去1的長度。

Sample input:

5

2 2

1 1

4 5

7 1

6 7

Sample output:

1

Hint:

1->2->4->5最短距離為2,答案為1。

對于30%的數據,n<=1000。

對于100%的數據,n<=200000,0<xi,yi<1e9

數據保證答案>0,不然很奇怪。。

?題解:我們發現每個點分別于橫縱坐標相鄰的點連邊就可以解決問題了,建邊后直接跑最短路就可以了。最后不要忘記答案-1.(可以自己構圖驗證正確性)

?用堆優化+dijistra的板子

#include <bits/stdc++.h> #include <algorithm> using namespace std; #define maxn 200005 #define maxm 1000005 bool vis[maxn]; int L,n,tot,head[maxn],dis[maxn]; inline void read(int &x){x=0;int f=1;char s=getchar();while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}x*=f; } struct Point{int x,y,id; }p[maxn]; struct edge{int nxt,v,w; }G[maxm]; struct rp{int id,key;rp(int a,int b){id=a, key=b;} }; bool cmp2(Point a, Point b){return a.x < b.x; } bool cmp1(Point a, Point b){return a.y < b.y; } struct cmp{bool operator()(const rp& a, const rp& b){return a.key > b.key;} };void add(int u, int v, int w){G[++tot].nxt = head[u];G[tot].w = w;G[tot].v = v;head[u] = tot;G[++tot].nxt = head[v];G[tot].w = w;G[tot].v = u;head[v] = tot; } void dijistra(){memset(dis, 127, sizeof(dis));priority_queue <rp,vector<rp>,cmp> q;q.push(rp(1, 0));dis[1] = 0;while(!q.empty()){rp u = q.top();q.pop();if(vis[u.id])continue;vis[u.id] = 1;for(int j = head[u.id]; j; j = G[j].nxt){int v = G[j].v;if(dis[v] > dis[u.id] + G[j].w){dis[v] = dis[u.id] + G[j].w;q.push(rp(v, dis[v]));}}} } int main() { freopen("run.in","r",stdin);freopen("run.out","w",stdout);read(n);for(int i = 1; i <= n; i++)read(p[i].x), read(p[i].y), p[i].id = i;sort(p+1, p+1+n, cmp2);for(int i = 1; i < n; i++)add(p[i].id, p[i+1].id, p[i+1].x - p[i].x);sort(p+1, p+1+n, cmp1);for(int i = 1; i < n; i++)add(p[i].id, p[i+1].id, p[i+1].y - p[i].y);dijistra();printf("%d\n",dis[n]-1); }

?

?

?

homework

Background:

??? ??? 小哪吒在開學前一天補作業。。。

Description:

??? ??? 明天就要開學了!所以小哪吒需要盡快寫完作業。現在,他有n份作業需要寫,因為小哪吒精通變化,他可以再變出兩只手來,所以他可以同時寫兩份作業。小哪吒兩雙手寫同一份作業的時間是不一樣的。為了節約時間,他用火眼睛睛看出了兩雙手寫同一份作業分別需要ai,bi的時間。同樣的,為了節約時間,他不會更改做題的順序,即他會從第一份作業一直做到第n份作業。他唯一不知道的是,他能寫完作業的最短時間。你能幫他求出來嗎?

Input:

??? ??? 第一行一個數n表示作業的數目。

????? ????? 接下來n行每行兩個數ai,bi分別表示小哪吒兩雙手寫這份作業的時間。

Output:

??? ??? 一行一個數表示寫作業的最短時間。

Sample input:

3
1 3
1 3
1 3

Sample output:

??? 3

Hint:

????? ????? 對于樣例,用第一雙手做完所有作業。

????? ????? 對于40%的數據,n<=20。

????? ????? 對于100%的數據,n<=2000。ai,bi<=3000。

?題解:我們用dp[i][0/1][j]表示去做第i份作業用第0/1只手時,另外一雙手還需要做j的時間才能做完作業的最小時間;

dp[i][j][k] = min( dp[i - 1][ j ][ k+a[i - 1][ j ] ] + a[i - 1][ j ], ?dp[i - 1][ j^1 ][ a[i - 1][ j^1 ] ] , 但我們有可能在0手有空時不一定用0手而是等1手完了用1手,

而這樣當?k+a[i - 1][ j ] ?= 0我們剛好就去用了空閑的手,故我們反著推就可以了,因為dp[i][j][k] k=0 時有可能那只手已經休息了很久了;

注意dp[i]中第i份作業還沒做,所以我們最后要加上剩下的時間

#include <bits/stdc++.h>using namespace std; #define maxn 2005 int dp[maxn][2][3005], a[maxn][2]; inline void read(int &x){x=0;int f=1;char s=getchar();while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}x*=f; }int main(){///freopen("homework.in","r",stdin);//freopen("homework.out","w",stdout);int n;read(n);for(int i = 1; i <= n; i++)read(a[i][0]), read(a[i][1]);memset(dp, 0x3f, sizeof(dp));dp[1][0][0] = dp[1][1][0] = 0;for(int i = 1; i <= n; i++)for(int j = 0; j < 2; j++)for(int k = 0; k <= 3000; k++){dp[i+1][j][max(0, k-a[i][j])] = min(dp[i+1][j][max(0, k-a[i][j])], dp[i][j][k]+a[i][j]);dp[i+1][j][max(0, a[i][j^1]-k)] = min(dp[i+1][j][max(0, a[i][j^1]-k)] , dp[i][j^1][k]+k);}int ans = 1e9;for(int j = 0; j < 2; j++)for(int k = 0; k <= 3000; k++)ans = min(ans, dp[n][j][k] + max(k, a[n][j]));printf("%d\n",ans); }

?

cut

Background:

??? ??? 伐木工Zxr非常懶惰了,所以他在伐木的時候只會找準木頭被蟲蛀過的腐朽的地方砍下去。

Description:

??? ??? 一塊有N-1處被蟲蛀過的地方,假設被蟲蛀過的地方長度不計。這n-1個蟲蛀將木頭分成了n塊,題目將依次給出這n塊木頭的長度。懶惰的zxr最多只想砍m次,并且希望可以借此把這塊木頭分得盡量均勻,即希望使砍伐后連續的木塊中最長的盡量短。這個時候聰明的你跳了出來“我不僅能算出這個最短長度,我還能算出方案數!”

Input:

????? ????? 第一行兩個數n,m。

????? ????? 接下來一行n個數分別表示這N塊木頭的長度。

Output:

????? ????? 一行兩個數分別表示最短的最長長度和方案數。

Sampleinput:

????? ????? 3 2

????? ????? 1 1 10

Sampleoutput:

????? ????? 10 2

Hint:

????? ????? 兩種砍的方法: (1)(1)(10)和(1 1)(10)。

????? ????? 對于30%的數據,n<=10,

????? ????? 對于100%的數據,n<=50000,

0<=m<=min(n-1,1000),1<=Li<=1000.

題解:

第一問是一個十分顯然的二分,貪心Check(),很容易就能求出最小的最大長度 Len 。

第二問求方案總數,使用 DP 求解。

  使用前綴和,令 Sum[i] 為前i根木棍的長度和。

  令 f[i][j] 為前i根木棍中切 j 刀,并且滿足最長長度不超過 Len的方案數,那么:

    狀態轉移方程: f[i][j] = Σ f[k][j-1]   ((1 <= k <= i-1) && ?(Sum[i] - Sum[k] <= Len))  

  這樣的空間復雜度為 O(nm) ,時間復雜度為 O(n^2 m) 。顯然都超出了限制。

  下面我們考慮 DP 的優化。

  1) 對于空間的優化。

    這個比較顯然,由于當前的 f[][j] 只與 f[][j-1] 有關,所以可以用滾動數組來實現。

    f[i][Now] 代替了 f[i][j] , f[i][Now^1] 代替了 f[i][j-1] 。為了方便,我們把 f[][Now^1] 叫做 f[][Last] 。

    這樣空間復雜度為 O(n) 。滿足空間限制。

  2) 對于時間的優化。

    考慮優化狀態轉移的過程。

    對于 f[i][Now] ,其實是 f[mink][Last]...f[i-1][Last] 這一段 f[k][Last] 的和,mink 是滿足 Sum[i] - Sum[k] <= Len 的最小的 k ,那么,對于從 1 到 n 枚舉的i,相對應的 mink 也一定是非遞減的(因為 Sum[i] 是遞增的)。我們記錄下 f[1][Last]...f[i-1][Last] 的和Sumf,mink 初始設為 1,每次對于i將 mink 向后推移,推移的同時將被舍棄的 p 對應的 f[p][Last] 從Sumf中減去。那么 f[i][Now] 就是Sumf的值。

    這樣時間復雜度為 O(nm) 。滿足時間限制。

#include <bits/stdc++.h>using namespace std; #define maxn 50005 #define mod 10007 int dp[maxn][2], a[maxn], sum[maxn], L, n, m, Ml; inline void read(int &x){x=0;int f=1;char s=getchar();while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}x*=f; }bool check(int mid){int ll = 0, i = 0, group = 1, flag = 0;while(i <= n){if(ll + a[++i] <= mid)ll += a[i];else if(a[i] > mid)return false;else {group++;if(group > m + 1)return false;ll = a[i];}}return true; } void bs(){int l = Ml, r = sum[n];while(l != r){int mid = (l + r) >> 1;if(check(mid))r = mid;else l = mid+1;}L = r;//取大的printf("%d ",L); } void Dp(){int sumf = 0, mink = 0, ans = 0;int k = 0;for(int j = 0; j <= m; j++){sumf = 0; mink = 1;//一定要記得更新,忘了更新這個地方,WA了好多次for(int i = 1; i <= n; i++){if(!j){if(sum[i] <= L)dp[i][k] = 1;}else {while(mink < i && sum[i] - sum[mink] > L){sumf -= dp[mink][k^1];sumf = (sumf + mod) % mod;mink++; } dp[i][k] = sumf;} sumf = (sumf + dp[i][k^1]) % mod;}ans += dp[n][k];ans %= mod;k^=1;//滾動數組 }printf("%d\n",ans); } int main(){freopen("cut.in","r",stdin);freopen("cut.out","w",stdout);read(n),read(m);for(int i = 1; i <= n; i++){read(a[i]);Ml = max(Ml, a[i]);sum[i] = sum[i-1] + a[i];}bs();Dp(); }

?

轉載于:https://www.cnblogs.com/EdSheeran/p/8496929.html

總結

以上是生活随笔為你收集整理的18寒假最后一测+dijistra模板的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。