4370 0 or 1
就2種情況, 一種是1到n的最短路, 一種是包含1的環和包含n的環, 第一種情況直接sssp就好, 第二種比較好的處理方法就是枚舉環的一個點, 然後用sssp得到的dist數組去求2個最小環, 相加即可,我的方法是再跑遍floyd, 不過要用dist優化一下, 提前排除不是最優解的情況, 1600ms水過
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
const int oo=2000000000;
const int maxn=100000+123;
const int inf=0x5fffffff;
int a[333][333];
struct Edge{
int v, w, next;
}edge[maxn*2];
int head[maxn], cnt;
struct Node{
int u, w;
bool operator < (Node a)const
{
return w > a.w;
}
};
void addedge(int u, int v, int w)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
int dist[maxn];
void Dijkstra(int s, int n)//0到n-1 s是源點
{
for (int i=0; i<n; ++i)
dist[i]=inf;
dist[s]=0;
priority_queue<Node> q;
Node cur;
cur.u=s; cur.w=0;
q.push(cur);
while (!q.empty())
{
cur=q.top();
q.pop();
if(dist[cur.u]<cur.w)continue;
for (int p=head[cur.u]; ~p; p=edge[p].next)
if(dist[edge[p].v]>dist[cur.u]+edge[p].w)
{
dist[edge[p].v]=dist[cur.u]+edge[p].w;
Node tmp;
tmp.u=edge[p].v;
tmp.w=dist[edge[p].v];
q.push(tmp);
}
}
//for (int i=0; i<n; ++i)cout << dist[i] << " ";
//cout << endl;
}
int main()
{
int n,t;
while (~scanf("%d",&n))
{
memset (head, -1, sizeof(head));
cnt=0;
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
{
scanf("%d",&a[i][j]);
addedge(i, j, a[i][j]);
}
Dijkstra(0, n);
for (int k=0;k<n;k++)
for (int i=0;i<n;i++)if(a[i][k]<dist[n-1])
for (int j=0;j<n;j++)if(a[k][j]<dist[n-1])
if (a[i][j]>a[i][k]+a[k][j])
a[i][j]=a[i][k]+a[k][j];
/*for (int i=0;i<n;i++)
{
for (int j=0;j<n;j++)
printf("%d ",a[i][j]);
printf("\n");
}*/
int ans=a[0][n-1];
int tmp1=oo, tmp2=oo;
for (int i=0; i<n; ++i)
{
if(i)tmp1=min(a[0][i]+a[i][0], tmp1);
if(i!=n-1)tmp2=min(a[n-1][i]+a[i][n-1], tmp2);
}
ans=min(ans, tmp1+tmp2);
printf("%d\n",ans);
}
return 0;
}
4371 Alice and Bob 博弈, 可以想到如果某次不取最小值去加,那麼下手下一步一定有棋可走, 所以雙方都每次都選擇加最小值是不影響勝局的。
hdu4374 One hundred layer dp 單調隊列優化
int M[123][12345];
int dp[123][12345];
int sum[12345];
int l[12345];
int r[12345];
int inl[12345];
int inr[12345];
int main ()
{
int n, m, x, t;
while (~scanf("%d%d%d%d", &n, &m, &x, &t))
{
for (int i=0; i<n; ++i)
{
for (int j=1; j<=m; ++j)
{
scanf("%d", &M[i][j]);
dp[i][j]=-inf;
}
}
dp[0][x]=0;
sum[0]=0;
for (int i=1; i<=m; ++i)
{
suf[m-i+1]=M[0][m-i+1]+suf[m-i+2];
dp[n][i]=-inf;
//printf("sss==%d ", suf[m-i+1]);
sum[i]=M[0][i]+sum[i-1];
}
for (int i=1; i<=m; ++i)
{
l[i]=dp[0][i]-sum[i-1];
r[i]=dp[0][i]+sum[i];
}
for (int i=1; i<=n; ++i)
{
int head=1, rear=0;
for (int j=1; j<=m; ++j)
{
while (head<=rear && l[inl[rear]]<=l[j])rear--;
inl[++rear]=j;
while (head<=rear && inl[head]<j-t)head++;
// for (int k=head; k<=rear; ++k)
// printf("l[%d]=%d ", inl[k], l[inl[k]]+sum[j]);
// printf("ll %d head=%d, rear==%d\n", j, head, rear);
dp[i][j]=max(l[inl[head]]+sum[j], dp[i][j]);
}
int top=1, tail=0;
for (int j=m; j>=1; --j)
{
while (top<=tail && r[inr[tail]]<=r[j])tail--;
inr[++tail]=j;
while (top<=tail && inr[top]>j+t)top++;
dp[i][j]=max(r[inr[top]]-sum[j-1], dp[i][j]);
// for (int k=top; k<=tail; ++k)
// printf("%d ", r[inr[k]]-sum[j-1]);
// printf("rr i==%d j==%d\n", i, j);
}
for (int j=1; j<=m; ++j)
{
sum[j]=M[i][j]+sum[j-1];
}
for (int j=1; j<=m; ++j)
{
l[j]=dp[i][j]-sum[j-1];
r[j]=dp[i][j]+sum[j];
}
}
// for (int i=0; i<=n; ++i)
// {
// for (int j=1; j<=m; ++j)
// printf("%d ", dp[i][j]);
// puts("");
// }
int ans=-inf;
for (int j=1; j<=m; ++j)
ans=max(dp[n][j], ans);
printf("%d\n", ans);
}
return 0;
}
/*
3 3 2 1
7 8 1
4 5 6
1 2 3
3 3 2 1
7 -8 10
4 5 6
1 2 3
3 3 2 1
-1 -1 -1
-1 -1 -1
-1 -1 -1
*/