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 */