http://acm.sdibt.edu.cn:8080/judge/contest/view.action?cid=573#problem/B
题意:求最大权值和,起点为1,终点为权值最大的那个点(其权值为负,而且在负数里最大),这题同时要求在到达负最大的权值那个点之前不能经过其他负数的点,
而且没经过一个点,就加上该点的wi,最后一个点也要加上|wi|
分析:刚开始我是搜索,纯搜,毫无疑问超时~~~
后来实在无法,搜了解题报告发现是记忆化搜索,不过自己敲出来一直wa,纠结了好久后才知道,原来在取可连通路径最大值那里错了
记忆化搜索
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int MN=110;
const int INF=0x7fffffff;
int map[MN][MN];
int num[MN];
int dp[MN];
int n,m;
int MIN;
int ans;
int e;
int DFS(int cur)
{
if(dp[cur]>=0) return dp[cur];
if(cur==e) return -MIN;
if(num[cur]==-INF) return 0;
int MAX=0;
for(int i=1; i<=n; i++)
{
if(cur==i) continue;
if(map[cur][i])
{
int tmp=DFS(i);
if(tmp>0) MAX=max(MAX,num[cur]+tmp);
//这里的tmp>0必须要有,因为当路径不可达的情况下
//递归所返回的值是0,而num[cur]>0这样必定比MAX=0
//大,而其i点本身不可达,又哪来的比较
}
}
return dp[cur]=MAX;
}
int main()
{
int i,j,a,b;
int flag;
while(scanf("%d%d",&n,&m)!=EOF)
{
flag=false;
memset(map,0,sizeof(map));
memset(dp,-1,sizeof(dp));
for(i=1; i<=m; i++)
{
scanf("%d%d",&a,&b);
map[a][b]=1;
}
MIN=99999;
num[1]=0;
for(i=2; i<=n; i++)
{
scanf("%d",&num[i]);
if(num[i]<0)
{
flag=true;
if(MIN>num[i])
{
MIN=num[i];
e=i;
}
}
}
for(i=2;i<=n;i++)
{//将所有小于最大负数的点赋予无穷,不可达
if(num[i]<0 && num[i]>MIN) num[i]=-INF;
}
ans=DFS(1);
if(ans==0 || flag==false) printf("What is a fucking day!\n");
else printf("%d\n",ans);
}
return 0;
}
BFS
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int MN=110;
const int INF=0x7fffffff;
int map[MN][MN];
int num[MN];
int mmax[MN];
int vis[MN];
int n,m;
int MIN;
int e;
int BFS(int e)
{
int i,j;
memset(vis,0,sizeof(vis));
memset(mmax,-1,sizeof(mmax));
queue<int>Q;
Q.push(1);
vis[1]=0;
mmax[1]=0;
while(!Q.empty())
{
int head=Q.front();
Q.pop();
for(i=1; i<=n; i++)
{
if(map[head][i])
{
if(num[i]>0)//这里加上vis==0是错的
{//因为vis的作用只是判断点是否进过队列
if(mmax[i]<mmax[head]+num[i])
mmax[i]=mmax[head]+num[i];
}
if(i==e)
{
if(mmax[i]<mmax[head]-num[i])
mmax[i]=mmax[head]-num[i];
}
if(num[i]>0 && vis[i]==0)
{
Q.push(i);
vis[i]=1;
}
}
}
vis[head]=0;
}
}
int main()
{
int i,j,a,b;
int flag;
while(scanf("%d%d",&n,&m)!=EOF)
{
flag=false;
memset(map,0,sizeof(map));
for(i=1; i<=m; i++)
{
scanf("%d%d",&a,&b);
map[a][b]=1;
}
MIN=99999;
num[1]=0;
for(i=2; i<=n; i++)
{
scanf("%d",&num[i]);
if(num[i]<0)
{
flag=true;
if(MIN>num[i])
{
MIN=num[i];
e=i;
}
}
}
for(i=2; i<=n; i++)
{
//将所有小于最大负数的点赋予无穷,不可达
if(num[i]<0 && num[i]>MIN) num[i]=-INF;
}
BFS(e);
if(mmax[e]>0) printf("%d\n",mmax[e]);
else printf("What is a fucking day!\n");
}
return 0;
}