1、P1570求
# KC 喝咖啡
题意:取若干个数,使得上述式子最大
思路:既然要求两个最大相减总和,那么对于一个答案x而言,每个i对它的贡献为,所以贪心取前i个最大的数,若贡献不为负数,即答案合法,注意精度1e-3,实际需要取到-0.02
#include<bits/stdc++.h>
using namespace std;
const int N = 210;
int n,m;
struct node{
double v,c,div;
}a[N];
inline bool cmp(node a,node b){
return a.div>b.div;
}
bool chk(double x){
double tot=0.0;
double g[N]={0.0};
for(int i=1;i<=n;i++) a[i].div=a[i].v*1.0-a[i].c*1.0*x;//计算贡献
sort(a+1,a+n+1,cmp);
//for(int i=1;i<=n;i++) printf("%.6f ",a[i].div);
for(int i=m;i>=1;i--) tot+=a[i].div;
if(tot>=-0.002) return true;
else return false;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i].v;
for(int i=1;i<=n;i++) cin>>a[i].c;
double l=0.0,r=1000.0;
while(r-l>1e-6){//精度在-0.02
double mid=(l+r)/1.0/2;
if(chk(mid)){
//cout<<chk(1.6667);
l=mid;
}
else r=mid;
}
printf("%.3f",l);
return 0;
}
2.P1948
# [USACO08JAN] Telephone Lines S
题意:在删除k条边后1-n路径上的最大值最小
思路:每次bfs求该条路径最大值,若需要删边,则储存删了j条边,在i处的最小值,并与新状态取min,运用答案判断该边是否要删
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int n,p,k,l,r;
struct node{
int y,w;
};
struct num{
int d,s,maxn;
};
vector<node> v[N];
int g[N][N*10];
bool chk(int x){
queue<num> q;
memset(g,0x3f,sizeof g);
q.push({1,0,0});
g[1][0]=0;
while(q.size()){
auto l=q.front();
q.pop();
//cout<<l.d<<" "<<l.s<<" "<<l.maxn<<endl;
if(l.d==n){
return true;
}
for(node t:v[l.d]){
int now=max(t.w,l.maxn);
if(now>x){
if(l.s<k&&l.maxn<g[t.y][l.s+1]){
q.push({t.y,l.s+1,l.maxn});//删边
g[t.y][l.s+1]=l.maxn;
}
}
else{
if(now<g[t.y][l.s]){
q.push({t.y,l.s,now});//不删边
g[t.y][l.s]=now;
}
}
}
}
return false;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>p>>k;
for(int i=1,x,y,w;i<=p;i++){
cin>>x>>y>>w;
v[x].push_back({y,w});
v[y].push_back({x,w});
r=max(r,w);
}
if(k>p){
return cout<<0,0;
}
while(l<r){
int mid=(l+r)>>1;
if(chk(mid)) r=mid;
else l=mid+1;
}
if(chk(l))
cout<<l;
else cout<<-1;
return 0;
}
注意最大值更小时才能更新,同时判断0的情况,即是可删边大于当前边数