1. 程式人生 > >貪心法(洛谷普及場1)

貪心法(洛谷普及場1)

#include<bits/stdc++.h>
#define fo(i,j,n) for(register int i=j;i<=n;++i)
#define ll long long
using namespace std;
priority_queue<int, vector<int>, greater<int>> pq;
int n,a,b;
int main(){
	scanf("%d",&n);
	fo(i,1,n){
		scanf("%d",&a);
		pq.push(a);	
	}
	ll ans = 0;
	fo
(i,1,n-1){ a=pq.top();pq.pop(); b=pq.top();pq.pop(); ans += a+b; pq.push(a+b); } printf("%lld\n", ans); return 0; }

P1181 數列分段Section I 題目連結:https://www.luogu.org/problemnew/show/P1181 解法一:從左到右倍增直到區間不能再增大為止 解法二:貪心,從左到右一直加到不滿足為止,然後重新加

#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std; const int maxn = 1e5+5; int n,m,a[maxn],sum[maxn]; void solve(){ int l=1,p=1,r=l,ans=0; while(l<=n){ ans++; r=l,p=1; while(p){ if(r+p>n){ p >>= 1;continue; } if(sum[r+p]-sum[l-1]<=m){ r += p; p <<= 1; }else{ p >>= 1;
} } l = r+1; // cout<<r<<endl; } printf("%d\n",ans); } void solve1(){ int ans=1,s=0,x; fo(i,1,n){ scanf("%d",&x); if(s+x<=m){ s+=x; }else{ ans++; s=x; } } printf("%d\n",ans); } int main(){ scanf("%d%d",&n,&m); // fo(i,1,n)scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i]; // solve(); // 倍增法,複習一下 solve1();// 直接倍增 return 0; }
#include<bits/stdc++.h>
#define ll long long 
#define mk make_pair
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n,m;
vector<pair<int,int> > ver; 
void solve(){
	sort(ver.begin(),ver.end());
	ll ans=0,all=0;
	for(auto p:ver){
		if(all+p.second<=n){
			ans += p.first*p.second;
			all += p.second;
		}else{
			ans += (n-all)*p.first;
			break;
		}
	}
	printf("%lld\n",ans);
} 
int main(){
	scanf("%d%d",&n,&m);
	int a,b;
	fo(i,1,m){
		scanf("%d%d",&a,&b);
		ver.push_back(mk(a,b));
	}
	solve();
	return 0;
}

P1223 排隊接水 題目連結:https://www.luogu.org/problemnew/show/P1223 題解: 微擾法證明: 要使總等待時間最少,每一次接水的是還沒接水的人中(m人)接水時間t1最少的 這時的後面的人的總等待時間為(m-1)t1,由於ti最小,則該局面下的總等待時間最小 設後面的某個人的等待時間為tk(tk>t1),排第k位(k>1) 這後面的人等待該人的總等待時間為 tk(m-k) 等待 這兩個人的總等待時間為 (m-1)t1+(m-k)tk = m(t1+tk) - t1-ktk = T1 若交換兩人位置,等待兩人的總等待時間為 (m-1)tk+(m-k)t1 = m(t1+tk) - tk-kt1 = Tk TK-T1 = -tk - kt1 + t1 + ktk = (k-1)*tk - (k-1)t1 = (k-1)(tk-t1)>0 所以任意非位置一(接水時間最少)的位置k,與位置一交換都會使得總等待時間變長 證畢。

#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
#define mk make_pair
using namespace std;
int n;
vector<pair<int,int> > ver;
int main(){
	scanf("%d",&n);
	int x;
	fo(i,1,n){
		scanf("%d",&x);
		ver.push_back(mk(x,i));
	}
	sort(ver.begin(),ver.end());//當ti重複時,按照輸入順序即可(sort是可以的)
	double sum=0.0,all=0.0;
	fo(i,0,n-1){
		all+=sum; // 加上ver[i].second,這位同學的等待時間 
		sum+=ver[i].first;// 計算下一位同學的等待時間 
		printf("%d%c",ver[i].second,i==n-1?'\n':' ');
	}
	printf("%.2f\n",all/n);
	return 0;
}
#include<bits/stdc++.h>
#define fo(i,j,n) for(register int i=j; i<=n;++i)
using namespace std;
int m,n,a[30005];
int main(){
	scanf("%d%d",&m,&n);
	fo(i,1,n)scanf("%d",&a[i]);
	sort(a+1,a+1+n);
	int ans=0,l=1,r=n;
	while(l<=r){
		if(a[r]+a[l]<=m){
			r--;l++;
			ans++;
		}else{
			r--; ans++;
		}
	}
	printf("%d\n",ans);
}

P1803 凌亂的yyy / 線段覆蓋 題目連結:https://www.luogu.org/problemnew/show/P1803 解法:右端點進行排序,每次選擇右端點儘量小的,如果該區間可以選擇的話,否則繼續選擇其他右端點儘量小的

#include<bits/stdc++.h>
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
#define mk make_pair
using namespace std;
int n;
vector<pair<int,int> > ver;
int main(){
	scanf("%d",&n);
	int a,b;
	fo(i,1,n)scanf("%d%d",&a,&b),ver.push_back(mk(b,a));
	sort(ver.begin(),ver.end());
	int ans = 0,last=0;
	fo(i,0,n-1){
		if(ver[i].second>=last){
			last=ver[i].first;
			ans++;
		}
	}
	printf("%d\n",ans);
	return 0;
}