House Man HDU - 3440 (差分约束+大概摸到了差分约束的本质)

传送门

题意:给出一组房子,房子有高度,并且只能从低房子跳到相应稍微高的房子,跳的长度还有限制,然后房子可以移动,但是序列不能动,没有两个房子处于同一个位置,现在问最高的房子位置在哪.

题解:首先根据房子不在同一位置可以得出s[i+1]-s[i]>=1,然后又根据跳的限制,把高度排好序后,之后还得处理下序号,都是小事,然后s[v]-s[u]<=u,之后还是都转换成<=号,然后就可以导出答案了。

感悟:这个题得到的感悟比较多,第一次我是用都转换成>=号做的,确实能做,进队我还用的超级源点,之后发现根本不对,用>=号就得倒着来,用<=号就是正着,用<=号就不用乱倒,很好,最后发现只要说求那两个点啥的,都用<=号比较好,输出答案之类用啥都行,尽量再画个图验证一番最好了。也是稍微感觉有点摸到了差分约束的本质,只要条件能找全,然后边缘处理好,入队方式处理处理,就没问题了。

附上代码:


#include<bits/stdc++.h>

using namespace std;

const int maxn=1100;
const int maxm=maxn*maxn*2;
const int inf=0x7fffffff;

struct edge{
    int v,w,next;
};
edge edges[maxm];
int head[maxn],tot;

void init()
{
    memset(head,-1,sizeof(head));
    tot=0;
}

void add_edges(int u,int v,int w)
{
    edges[tot].v=v;
    edges[tot].w=w;
    edges[tot].next=head[u];
    head[u]=tot++;
}

struct house{
    int hight,no;
};
house arr[maxn];

bool cmp(house a,house b)
{
    return a.hight<b.hight;
}

int n,d;
int dist[maxn],cnt[maxn];
bool vis[maxn];

int spfa(int s,int t)
{
    queue<int>q;
    for(int i=1;i<=n;i++){
        cnt[i]=0;dist[i]=inf;vis[i]=false;
    }
    q.push(s);
    dist[s]=0;vis[s]=true;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        if(++cnt[u]>n){
            return -1;
        }
        vis[u]=false;
        for(int i=head[u];i!=-1;i=edges[i].next){
            int v=edges[i].v,w=edges[i].w;
            if(dist[v]>dist[u]+w){
                dist[v]=dist[u]+w;
                if(!vis[v]){
                    vis[v]=true;
                    q.push(v);
                }
            }
        }
    }
    return dist[t];
}

int main()
{
    int T,casen=1;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d%d",&n,&d);
        for(int i=1;i<=n;i++){
            scanf("%d",&arr[i].hight);
            arr[i].no=i;
            if(i!=n){
                add_edges(i+1,i,-1);
            }
        }
        sort(arr+1,arr+n+1,cmp);
        for(int i=1;i<n;i++){
            int u=arr[i].no,v=arr[i+1].no;
            if(u>v){
                swap(u,v);
            }
            add_edges(u,v,d);
        }
        int u=arr[1].no,v=arr[n].no;
        if(u>v){
            swap(u,v);
        }
        printf("Case %d: %d\n",casen++,spfa(u,v));
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值