题目链接:https://cn.vjudge.net/contest/276233#problem/D
具体大意:
给出n个闭合的整数区间[ai,bi]和n个整数c1,…,cn。
编写一个程序:
从标准输入中读取间隔数,它们的端点和整数c1,…,cn,
计算具有间隔[ai,bi]的至少ci共同元素的整数集合Z的最小尺寸,对于每个i = 1,2,…,n,
将答案写入标准输出。
具体思路:首先,我们假设存在一个数组s,s[i]记录的是第i个点到第0个点的需要取出的点的个数,对于题目中的从(A,B)至少有d个,我们就可以将这个条件变成posB-(posA-1)>=d,也就是(posA-1)-posB<=-d,这一段的边就建立好了,但是对于这个区间内的每一个数,我们的范围是没有限制的,但是如果没有限制会出现下列情况,s[i]>=i,也就是说会出现矛盾,所以对于这个区间内的没一个数都需要限制,也就是对于区间(i,i+1),我们可以引申出如下条件。0=<pos(i+1)-pos(i)<=1,
也就是 pos[i+1]-pos[i]>=0(pos[i]-pos[i+1]<=0),和 pos[i+1]-pos[i]<=1,也就是把这段区间的每一个小的区间的条件设立好了就可以了。(注意建边的时候注意方向)
AC代码:
#include<iostream>
#include<cstring>
#include<stack>
#include<iomanip>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stdio.h>
using namespace std;
# define ll long long
# define inf 0x3f3f3f3f
const int maxn = 50000+100;
const int maxedge= 1000000+10;
int num,head[maxn];
int dis[maxn],vis[maxn];
int minx=inf;
int maxy=0;
struct node
{
int fr;
int to;
int cost;
int nex;
} edge[maxedge];
struct point
{
int st;
int ed;
} po[maxn];
void init()
{
for(int i=0; i<=50000; i++)
{
head[i]=-1;
vis[i]=0;
dis[i]=inf;
}
num=0;
}
void addedge(int fr,int to,int cost)
{
edge[num].to=to;
edge[num].cost=cost;
edge[num].nex=head[fr];
head[fr]=num++;
}
ll spfa(int st,int ed)
{
dis[st]=0;
vis[st]=1;
queue<int>q;
q.push(st);
while(!q.empty())
{
int tmp=q.front();
q.pop();
vis[tmp]=0;
for(int i=head[tmp]; i!=-1; i=edge[i].nex)
{
int u=edge[i].to;
if(dis[u]>dis[tmp]+edge[i].cost)
{
dis[u]=dis[tmp]+edge[i].cost;
if(vis[u])
continue;
vis[u]=1;
q.push(u);
}
}
}
return dis[ed];
}
int main()
{
int n,d;
scanf("%d",&n);
init();
for(int i=1; i<=n; i++)
{
scanf("%d %d %d",&po[i].st,&po[i].ed,&d);
addedge(po[i].st-1+1,po[i].ed+1,-d);//两个左边都+1,是为了防止出现变成-1的情况。
minx=min(minx,po[i].st);
maxy=max(maxy,po[i].ed+1);
}
for(int i=minx; i<=maxy-1; i++)
{
addedge(i,i+1,0);
addedge(i+1,i,1);
}
int ans=spfa(minx,maxy);
printf("%d\n",-ans);
return 0;
}
E题:
一个由memset引发的惨案,,,本来是用for循环初始化来着,结果这个题用for一直wa(后来发现是越界了--),然后改成memset的化就给过了。但是顺便加深了对建图的理解(理解写在上面了)。
AC代码:
#include<iostream>
#include<cstring>
#include<stack>
#include<iomanip>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stdio.h>
using namespace std;
# define ll long long
# define inf 0x3f3f3f3f
const int maxn = 50000+100;
const int maxedge= 1000000+10;
int num,head[maxn],out[maxn];
int dis[maxn],vis[maxn];
int n,m;
struct node
{
int fr;
int to;
int cost;
int nex;
} edge[maxedge];
struct point
{
int st;
int ed;
} po[maxn];
void init()
{
for(int i=0; i<maxn; i++)
{
vis[i]=0;
dis[i]=inf;
head[i]=-1;
out[i]=0;
}
num=0;
num=0;
}
void addedge(int fr,int to,int cost)
{
edge[num].to=to;
edge[num].cost=cost;
edge[num].nex=head[fr];
head[fr]=num++;
}
ll spfa(int st)
{
dis[st]=0;
vis[st]=1;
queue<int>q;
q.push(st);
while(!q.empty())
{
int tmp=q.front();
q.pop();
if(++out[tmp]>n+3)
return -1;
vis[tmp]=0;
for(int i=head[tmp]; i!=-1; i=edge[i].nex)
{
int u=edge[i].to;
if(dis[u]>dis[tmp]+edge[i].cost)
{
dis[u]=dis[tmp]+edge[i].cost;
if(vis[u])
continue;
vis[u]=1;
q.push(u);
}
}
}
return 1;
}
int main()
{
while(cin>>n)
{
init();
if(n==0)
break;
cin>>m;
int u,v,d;
string str;
for(int i=1; i<=m; i++)
{
cin>>u>>v>>str>>d;
if(str=="gt")
{
addedge(u,u+v+1,-(d+1));
}
else
{
addedge(v+u+1,u,d-1);
}
}
for(int i=1; i<=n+1; i++)
{
addedge(102,i,0);//超级源点的建立过程
}
int ans=spfa(102);
if(ans==-1)
cout<<"successful conspiracy"<<endl;
else
cout<<"lamentable kingdom"<<endl;
}
return 0;
}
G题:超级源点的建立,为了保证整个区间的连通的,我们就需要建立一个超级源点来使得整个图是连通的,但是注意一点,在正常建边的时候,如果是大的指向小的,这个时候我们建立超级源点的时候就也应该遵循这个原则,如果是是小的指向大的,我们建立超级源点的时候反过来就可以了。
AC代码:
#include<iostream>
#include<cstring>
#include<stack>
#include<iomanip>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stdio.h>
using namespace std;
# define ll long long
# define inf 0x3f3f3f3f
const int maxn = 10000+100;
const int maxnedge=1000000+100;
struct node
{
int nex;
int to;
int cost;
} edge[maxnedge];
int head[maxn],vis[maxn],dis[maxn],num;
void init()
{
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(dis,inf,sizeof(dis));
num=0;
}
void addedge(int fr,int to,int cost)
{
edge[num].to=to;
edge[num].nex=head[fr];
edge[num].cost=cost;
head[fr]=num++;
}
int spfa(int st,int ed)
{
queue<int>q;
dis[st]=0;
vis[st]=1;
q.push(st);
while(!q.empty())
{
int tmp=q.front();
q.pop();
vis[tmp]=0;
for(int i=head[tmp]; i!=-1; i=edge[i].nex)
{
int u=edge[i].to;
if(dis[u]>dis[tmp]+edge[i].cost)
{
dis[u]=dis[tmp]+edge[i].cost;
if(vis[u])
continue;
vis[u]=1;
q.push(u);
}
}
}
return dis[ed];
}
int main()
{
init();
int n;
scanf("%d",&n);
int u,v;
int minx=inf,maxy=0;
for(int i=1; i<=n; i++)
{
scanf("%d %d",&u,&v);
u+=10;
v+=10;
addedge(u-1,v,-2);
addedge(v,u-1,v-u+1);
minx=min(minx,u-1);
maxy=max(maxy,v);
}
int st=maxy+1;
//cout<<minx<<" "<<maxy<<endl;
for(int i=minx; i<maxy; i++)
{
addedge(st,i,0);
addedge(i,i+1,0);
addedge(i+1,i,1);
}
addedge(st,maxy,0);
int ans=spfa(st,maxy);
printf("%d\n",-ans);
return 0;
}