【题目描述】
呐,贵树真的是一个很帅的男孩子呢,所以好多女孩都给他写至少一封
了情书。那每个女孩给了贵树写了多少情书呢?我们不知道,但是我们知
道一些女孩子写情书数量的关系,你的任务是推断出贵树最少受到了多少
情书。
【输入文件】
输入的第一行为两个整数 N,K,表示一共 N 个女孩,知道 K 对关系
接下来 K 行,每行三个整数 t,A,B
如果 t=1,则表示 A 的情书和 B 的情书数量一样
如果 t=2,则表示 A 的情书少于 B 的情书数量
如果 t=3,则表示 A 的情书不少于 B 的情书数量
如果 t=4,则表示 A 的情书多于 B 的情书数量
如果 t=5,则表示 A 的情书不多于 B 的情书数量
【输出文件】
一行,表示贵树满足这些关系时最少情况下收到情书的数量。
如果这些关系不可能同时被满足,则输出 -1。
【样例输入】
5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1
【样例输出】
11
【数据规模】
对于 30% 数据,保证 N <=100
其实通过观察我们可以发现比如三个不等式 ,b-a<=k1,c-b<=k2,c-a<=k3,求出c-a的最大值,我们可以把a,b,c转换成三个点,k1,k2,k3是边上的权
![](https://img-blog.csdn.net/20151021183328644?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
呐,贵树真的是一个很帅的男孩子呢,所以好多女孩都给他写至少一封
了情书。那每个女孩给了贵树写了多少情书呢?我们不知道,但是我们知
道一些女孩子写情书数量的关系,你的任务是推断出贵树最少受到了多少
情书。
【输入文件】
输入的第一行为两个整数 N,K,表示一共 N 个女孩,知道 K 对关系
接下来 K 行,每行三个整数 t,A,B
如果 t=1,则表示 A 的情书和 B 的情书数量一样
如果 t=2,则表示 A 的情书少于 B 的情书数量
如果 t=3,则表示 A 的情书不少于 B 的情书数量
如果 t=4,则表示 A 的情书多于 B 的情书数量
如果 t=5,则表示 A 的情书不多于 B 的情书数量
【输出文件】
一行,表示贵树满足这些关系时最少情况下收到情书的数量。
如果这些关系不可能同时被满足,则输出 -1。
【样例输入】
5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1
【样例输出】
11
【数据规模】
对于 30% 数据,保证 N <=100
对于 100% 数据,保证 N <=100000
看完这道题的感受就是“意~”,多么玛丽苏的题目orz,这道题乃某神犇看完秒速五厘米后有感而作(ヾ(。`Д´。)题意和题目完全没有关系好吗woc)
最开始用的方法只过了20分= =,后面的要么WA,要么超时,特将错误代码贴出留作纪念= =
注意是错误的!!
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int INF=0x7f7f7f;
struct node
{
int u,v;
int cmp;//两个数的关系
}e[400005];
int t,a,b;
int n,k;
int f[100005];//i个女生最少会给的数量
int num[100005];//每个女生最少会给的数量
bool flag=false;
int main()
{
freopen("love.in","r",stdin);
freopen("love.out","w",stdout);
scanf("%d %d",&n,&k);
memset(f,INF,sizeof(f));
for(int i=1;i<=n;i++)
{
num[i]=1;//初始每个人送了1封
}
for(int i=1;i<=k;i++)
{
scanf("%d %d %d",&t,&a,&b);
e[i].u=a;
e[i].v=b;
e[i].cmp=t;//a和b满足t的关系
if(t==1) num[a]=num[b];
if(t==2) num[b]=num[a]+1;
if(t==3) num[a]=num[b];
if(t==4) num[a]=num[b]+1;
if(t==5) num[a]=num[b];
}
for(int i=1;i<=k;i++)//不能满足flag=true
{
for(int j=1;j<=k;j++)
{
if((e[i].u==e[j].u&&e[i].v==e[j].v)||(e[i].u==e[j].v&&e[i].v==e[j].u))
{
if((e[i].cmp==1&&e[j].cmp==2)||(e[i].cmp==1&&e[j].cmp==4)||(e[i].cmp==4&&e[j].cmp==2))//1,2,4不能同时满足
{
flag=true;
printf("%d",-1);
return 0;
}
if((e[i].cmp==2&&e[j].cmp==3)||(e[i].cmp==4&&e[j].cmp==5))//2,3不能同时满足
{
flag=true;
printf("%d",-1);
return 0;
}
}
}
}
if(flag==false)
{
for(int i=1;i<=k;i++)
{
if(e[i].cmp==1) num[e[i].u]=max(num[e[i].u],num[e[i].v]);
if(e[i].cmp==2) num[e[i].v]=num[e[i].u]+1;
if(e[i].cmp==3) num[e[i].u]=max(num[e[i].u],num[e[i].v]);
if(e[i].cmp==4) num[e[i].u]=num[e[i].v]+1;
if(e[i].cmp==5) num[e[i].u]=max(num[e[i].u],num[e[i].v]);
}
}
/*for(int i=1;i<=n;i++)
{
printf("%d\n",num[i]);
}*/
f[0]=0;
for(int i=1;i<=n;i++)
{
f[i]=min(f[i],f[i-1]+num[i]);
}
printf("%d",f[n]);
return 0;
}
其实通过观察我们可以发现比如三个不等式 ,b-a<=k1,c-b<=k2,c-a<=k3,求出c-a的最大值,我们可以把a,b,c转换成三个点,k1,k2,k3是边上的权
所以题目就可以通过比较k1+k2和k3大小,求出的就是c-a的最大值了。
所以求解过程实际就是求从a到c的最短路径。
现在回到这道题上,就需要把不等式转化为x-y>=z的形式,寻找最长路
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,k;
struct node
{
int to,next;
int value;
}e[400005];
int head[100005];
int m=0;
int queue[100005];
int qhead=0;
int tail=1;
int dis[100005];//记录增加的情书数量
bool v[100005];
int bb[100005];// 记录入队次数
bool flag;
void add(int u,int v,int w)//加边
{
m++;
e[m].to=v;
e[m].next=head[u];
e[m].value=w;
head[u]=m;
}
void read()
{
freopen("love.in","r",stdin);
freopen("love.out","w",stdout);
memset(v,false,sizeof(v));
memset(dis,-1,sizeof(dis));//****
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
add(0,i,0);
}
for(int i=1;i<=k;i++)
{
int a,b,t;
scanf("%d%d%d",&t,&a,&b);
if(t==1)//当t==1时,a=b
{
add(a,b,0);
add(b,a,0);
}
if(t==3) add(b,a,0);//分类对5种情况进行赋值,当a>=b||a<=b时,因为求最小所以去=的情况,边的权值赋为0
if(t==5) add(b,a,0);
if(t==2) add(a,b,1);//当a>b||b>a时,边的权值赋为1
if(t==4) add(b,a,1);
}
}
void spfa()
{
tail++;
queue[tail]=0;
dis[0]=0;
v[0]=true;
while(tail>qhead)
{
int p=queue[++qhead];
v[p]=false;
int p1=head[p];
while(p1!=0)//
{
if(dis[e[p1].to]<dis[p]+e[p1].value)//当找到一个
{
dis[e[p1].to]=dis[p]+e[p1].value;
if(!v[e[p1].to])
{
queue[++tail]=e[p1].to;
bb[e[p1].to]++;
v[e[p1].to]=true;
if(bb[e[p1].to]>=n)//判断入队次数,如果入队次数大于n则存在环
{
printf("-1\n");
flag=true;
return;
}
}
}
p1=e[p1].next;
}
}
int ans=n;//因为每个人至少送1封,所以ans初值为n
if(flag==false)
{
for(int i=1;i<=n;i++)
{
ans+=dis[i];
}
printf("%d ",ans);
}
}
int main()
{
read();
spfa();
return 0;
}