算法竞赛(二分) (上午)

图论+二分

P1462

//邻接表实现无边权
vector<int> g[maxn];
g[x]push_back(y);
g[y]push_back(x);	


//边权实现
#include <vector>
using namespace std;

const int maxn = 1000;  // 最大节点数
vector<pair<int, int>> g[maxn];  // g[i] 表示节点 i 的邻接表,pair<int, int> 中第一个 int 是相邻的节点,第二个 int 是边的权重

void addEdge(int x, int y, int z) {
    g[x].push_back({y, z});  // 添加边 x -> y,权重为 z
    g[y].push_back({x, z});  // 添加边 y -> x,权重为 z(无向图)
}
//题解
#include<bits/stdc++.h>
using namespace std;
const int N = 10010;
long long f[N];//点的费用 
vector< pair< int , long long> >vec[N];//存边 
priority_queue< pair< long long, int > >que;
int vis[N];
long long dis[N];
long long b, v;
int n, m, x, y;
int check(int x)
{
	if(f[1] > x) return 0;//如果第一个点就不能走,直接返回不行 
	for(int i = 1; i <= n; ++ i){
		dis[i] = 1e18;//必备的初始化,没有会致错 
		vis[i] = 0;
	}
	dis[1] = 0;
	que.push(make_pair(0, 1));//修改的dijk 
	while(!que.empty()){
		int u = que.top().second;
		que.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		for(int i = 0; i < vec[u].size(); ++ i){
			int v = vec[u][i].first;
			if(f[v] > x) continue;//如果新拓展的点不符合要求,继续寻找 
			long long w = vec[u][i].second;
			if(dis[u] + w < dis[v]){
				dis[v] = dis[u] + w;
				que.push(make_pair(-dis[v], v));
			if(v == n){//如果已经到达,判断是否生命值有剩余 
				if(dis[n] >= b) return 0;
				else return 1;
			}	
		}
	}
}
	return 0;//如果没有到达,直接返回不行 
}
int main()
{
	long long mxx = -1;
	scanf("%d%d%lld", &n, &m, &b);
	for(int i = 1; i <= n; ++ i){
		scanf("%lld", &f[i]);
		mxx = max(mxx, f[i]);//寻找上边界 
	}
	for(int i = 1; i <= m; ++ i){
		scanf("%d%d%lld", &x, &y, &v);
		vec[x].push_back(make_pair(y, v));
		vec[y].push_back(make_pair(x, v));
	}
	long long ans = -1, l = 1, r = mxx;
	while(l <= r){
		long long mid = (l + r) / 2;
		if(check(mid)) ans = mid, r = mid - 1;//更形ans 
		else	l = mid + 1;
	}
	if(ans == -1) puts("AFK");//如果每次都没有扩展成功说明不能到达 
	else printf("%lld\n", ans);
	return 0;
}

//初始化方式

 // 使用 make_pair
    vec[0].push_back(std::make_pair(1, 2));

 // 使用列表初始化
    vec[1].push_back({3, 4});

二分进击奶牛

奶牛

点击查看代码(自己写的tle)
#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+10;
int n,c;
int a[maxn]= {0};
int d[maxn];
bool check(int mid)
{
	int cnt=0;
	for(int i=1; i<=n; i++)
		if(d[i]<mid)cnt++;
	if(cnt>=c)
		return false;
	return true;
}
int bs(int l,int r)
{
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(check)
			r=mid;
		else
			l=mid+1;

	}
	return l;
}
int main()
{
	cin>>n>>c;
	for(int i=1; i<=n; i++)
	{
		cin>>a[i];
		d[i]=a[i]-a[i-1];
	}

	cout<<bs(1,maxn/2);


	return 0;
}

1.没排序2.取出一个牛后没有更新距离3.好像破坏了d[i]数组?

最后其实是因为理解错题目了,是c头牛,、
然后就是<c,=c,>c,当我们要找最右侧的等于c,我们应该从这点分开,分成>c和<=c,两段才好。


算法竞赛(二分)(下午)

实数二分

#define eps=1e-5;
double pi=acos(-1.0);

分蛋糕

http://poj.org/problem?id=3122

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef  long long LL;
const int inf = 1<<30;
const LL maxn = 1e4+10;
const double pie =  3.1415926535897932;
const double eps = 1e-8;

int N, F;
double a[maxn];
bool check(double r){
    //所有派是否可以分成F份半径为r的
    int cnt = 0;
    for(int i = 1; i <= N; i++)
        //a[i]最多内可以划分几个r半径的小圆
        cnt += (int)(a[i]/r);  //内接圆公式
    return cnt >= F;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        double sum = 0;
        scanf("%d%d",&N,&F);
        ++F;

        for(int i = 1; i <= N; i++){
            scanf("%lf",&a[i]);
            a[i] *= a[i];
            sum += a[i];
        }

        double l = 0, r = sum/F, mid;
        while(r-l > eps){
            mid = (l+r)/2;
            if(check(mid)) l = mid;
            else r = mid;
        }
        printf("%.4lf\n", pie*l);
    }

	return 0;
}

寻找第k小的数(优化)

1923

image

stl

image

课后例题

1 线性动态规划(butaidong

https://www.luogu.com.cn/problem/P1868
image

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
vector<int>beg[3000010];//有点大,不过并不会 MLE
int n,mx,f[3000010];//mx 代表最大的 y,f 就是 dp 用的数组
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		beg[y].push_back(x-1);//这里保存的是 x-1,后面会比较方便
		mx=max(mx,y);
	}
	for(int i=1;i<=mx;i++){
		f[i]=f[i-1];//先设定为 f[i-1],后面再更新
		for(int j=0;j<beg[i].size();j++){
			int b=beg[i][j];
			f[i]=max(f[i],f[b]+i-b);//这里会比较方便
		}
	}
	printf("%d\n",f[mx]);
	return 0;
}

二分+前缀和 质检员

https://www.luogu.com.cn/problem/P1314

#include<bits/stdc++.h>
using namespace std;
const int maxn=200010;
int w[maxn],v[maxn],l[maxn],r[maxn];
long long pre_n[maxn],pre_v[maxn];
long long Y,s,sum;
int n,m,mx=-1,mn=2147483647;
bool check(int W)
{	
	Y=0,sum=0;
	memset(pre_n,0,sizeof(pre_n));
	memset(pre_v,0,sizeof(pre_v));
	for(int i=1;i<=n;i++)
	{
		if(w[i]>=W) pre_n[i]=pre_n[i-1]+1,pre_v[i]=pre_v[i-1]+v[i];
		else pre_n[i]=pre_n[i-1],pre_v[i]=pre_v[i-1];
	}
	for(int i=1;i<=m;i++)
		Y+=(pre_n[r[i]]-pre_n[l[i]-1])*(pre_v[r[i]]-pre_v[l[i]-1]);
		

	sum=llabs(Y-s);
	if(Y>s) return true;
	else return false;
	
}

int main(){
//	freopen("qc.in","r",stdin);
//	freopen("qc.out","w",stdout); 
	scanf("%d %d %lld",&n,&m,&s); 
	for(int i=1;i<=n;i++)
	{
		scanf(" %d %d",&w[i],&v[i]);
		mx=max(mx,w[i]);
		mn=min(mn,w[i]);	
	}
	for(int i=1;i<=m;i++)
		scanf(" %d %d",&l[i],&r[i]);
	int left=mn-1,right=mx+2,mid;  //这里有的人说要特判左右端点的check,但是其实你把left开成mn-1,right开成mx+2(注意取mx+1时即为W比所有都大,Y是0,这个情况要考虑,所以+2包含mx+1)就可以包含左右端点的check了,会简单点。
	long long ans=0x3f3f3f3f3f3f3f3f;//ll 范围内的无穷大,近似于(maxll/2)的大小
	while(left<=right)
	{
		mid=(left+right)>>1;
		if(check(mid)) 	left=mid+1;
		else right=mid-1;
		if(sum<ans) ans=sum;
	}
	printf("%lld",ans);
	return 0;
} 

图论(今日讲课)

floyd

image

初始化:
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= n; j ++ )
            if (i == j) d[i][j] = 0;
            else d[i][j] = INF;

// 算法结束后,d[a][b]表示a到b的最短距离
void floyd()
{
    for (int k = 1; k <= n; k ++ )
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}

image
image
邻接矩阵通常用于顶点较少的图,或者边的个数接近顶点个数的平方的图,也就是稠密图。
image

//假如当前点是u,使用其实现Dijkstra算法的松弛操作为例
for (auto v : G[u])
{
if (dis[v.first] > dis[u] + v.second)
{
dis[v.first] = dis[u] + v.second;
que.push({dis[v.first], v.first});
}
}

【金山文档 | WPS云文档】 图论基础
https://kdocs.cn/l/cjaYim9ZI71R

posted on 2024-07-24 09:34  Hoshino1  阅读(2)  评论(0编辑  收藏  举报