二分搜索题

本文深入探讨了Havel-Hakimi定理,这是一种用于判断一个非负整数序列是否可以作为某个无向图的度序列的方法。通过三个具体的编程实例,展示了如何在实际问题中应用这一理论,包括验证序列的可图化性质、求解数值范围问题以及优化路径选择算法。
摘要由CSDN通过智能技术生成

定义:对于一个非负整数组成的序列,如果存在一个无向图的度序列和其一致,则该序列是可图的。

Havel-Hakimi定理:给定一个非负整数序列{d1,d2,...dn},若存在一个无向图使得图中各点的度与此序列一一对应,则称此序列可图化。

由非负整数组成的有限非递增序列,S={d1,d2,d3...dn},当且仅当S1={d2-1,d3-1...d(d1+1)-1,d(d1+2),d(d1+3),......dn}也是可图的

 

三题的解释都写注释里面了,懒得分开写,感觉写注释里清楚一点。
poj1659

 

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std; 
const int N=15;
typedef struct hu{
    int id;
    int nu;
}hu;
hu num[N];
int t;
bool guan[N][N];
bool cmp(hu a,hu b){
    return a.nu>b.nu;
}
bool f(int k)//k cur
{
    sort(num+k,num+t+1,cmp);
    if(num[t].nu<0)return 0;
    if(k==t)return 1;
    for(int i=k+1;i<=k+num[k].nu;i++)
    {
        num[i].nu--;
        guan[num[i].id][num[k].id]=guan[num[k].id][num[i].id]=1;
    }
    f(k+1);
}
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        cin>>t;
        for(int i=1;i<=t;i++)
        {
            cin>>num[i].nu;
            num[i].id=i;
        }
        memset(guan,0,sizeof(guan));
        if(f(1))
        {
            cout<<"YES"<<endl;
            for(int i=1;i<=t;i++)
            {
                for(int j=1;j<=t;j++)
                {
                    cout<<guan[i][j]<<' ';
                }
                cout<<endl;
            }

    cout<<endl;
        }
        else cout<<"NO"<<endl<<endl;
    }
}

 

poj2018

#include<iostream>
#define max(x,y) (x>y)?(x):(y)
#define min(x,y) (x<y)?(x):(y)
using namespace std;
const int N=100005;
double a[N];
double sum[N];
double d[N];
double sumd[N];
int main()
{
    int n,f;
    cin>>n>>f;
    double maxx=0,minn=1e8;
    sum[0]=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        maxx=max(maxx,a[i]);//取区间最大值 
        minn=min(minn,a[i]);//取区间最小值 
    }
    int count=0;
    while(maxx-minn>1e-4)//二分,精度题目中限定了三位小数 
    {
        double mid=(maxx+minn)/2; 
        double maxxx=-1e8;
        double minnn=1e8;
        for(int i=1;i<=n;i++)
        {
            d[i]=a[i]-mid;//每个数减去当前的均值,很好的一个技巧,把对均值的增加减少的贡献,化为正负好判断
            sumd[i]=sumd[i-1]+d[i];//前缀和 
        }
        for(int i=f;i<=n;i++)//dp 
        {
            minnn=min(minnn,sumd[i-f]); 
            maxxx=max(maxxx,sumd[i]-minnn);
        }
        if(maxxx>=0)minn=mid;
        else maxx=mid;
    }
    cout<<int(maxx*1000)<<endl;
}

 

codeforces1073c

#include<iostream>
#include<string.h>
#include<string>
using namespace std;
#define abs(x) ((x>=0)?(x):(-x))
const int N=200005;
const int INF=0x3f3f3f3f;
int x[N];
int y[N];
int endx,endy;
int n;
bool check(int m)
{
    for(int i=1;i+m-1<=n;i++){
        int xx=x[n]-x[i+m-1]+x[i-1];
        int yy=y[n]-y[i+m-1]+y[i-1];
        //从i到i+m-1删去,即整个序列[1,i-1]+[m,n]的和  
        //tx ty是要修改的区间修改后应该对应的x和y
        int tx=endx-xx;
        int ty=endy-yy;
        //二者的差值 
        //区间长m>=|tx|+|ty|而且m与|tx|+|ty|同奇偶,剩下的两两相消
        if(abs(tx)+abs(ty)<=m &&(m-abs(tx)-abs(ty))%2==0)return true;
    }
    return false;
}
int main()
{
    string s;
    while(cin>>n){
    cin>>s;
    cin>>endx>>endy;
    memset(x,0,sizeof(x));
    memset(y,0,sizeof(y));
    
    for(int i=1;i<=s.length();i++)
    {
        switch(s[i-1])
        {
            case 'U':
                x[i]=x[i-1];
                y[i]=y[i-1]+1;
                break;
            case 'D':
                x[i]=x[i-1];
                y[i]=y[i-1]-1;
                break;
            case 'L':
                y[i]=y[i-1];
                x[i]=x[i-1]-1;
                break;
            case 'R':
                y[i]=y[i-1];
                x[i]=x[i-1]+1;
                break;
        }
    }
    //二分 区间长度 
    int l=0,r=n;
    int mid,ans=INF;     
    while(l<=r){
        mid=(l+r)>>1;
        if(check(mid)){
            r=mid-1;
            ans=mid;
        }
        else
        {
            l=mid+1;
        }
    }
    if(ans==INF)
    {
        cout<<"-1"<<endl;
    }
    else
    {
        cout<<ans<<endl;
    }
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值