挪酒瓶 牛客小白月赛33

原题链接

考察:思维

看半天没看出来,还以为和求最短交换次数差不多...实际完全不一样.菜狗不配...

思路:

        

           如果我们再交换a1和a4就可以化为更小的环.每步交换都是两个权值之和.因此假设a1是环中最小的,就由贪心得交换的最小权值和是4*w1+w2+w3+w4+w5

           但是如果这样贪心交上去依然WA,下面的测试数据可以卡掉这种做法:

5
1 3 4 5 2
1 90 90 90 90

         可以发现环中的再怎么交换都不如将1号酒瓶也换到环中的做法.所有最优解是每个环两者做法取最小值再累加.

 1 #include <iostream>
 2 #include <cstring>
 3 #include <vector>
 4 #include <set>
 5 using namespace std;
 6 const int N = 100010,INF = 0x3f3f3f3f;
 7 int n,p[N],w[N],minv = INF;
 8 bool st[N];
 9 int solve()
10 {
11     int res = 0;
12     for(int i=1;i<=n;i++)
13       if(p[i]!=i)
14       {
15            int sum = 0,cnt = 0,mins = INF;
16            if(st[i]) continue;
17            for(int k=i;!st[k];k = p[k])
18            {
19                st[k] = 1;
20                sum+=w[k];
21                cnt++;
22                mins = min(w[k],mins);
23          }
24          res += sum+min(minv*(cnt+1)+mins,mins*(cnt-2));
25       }
26     return res;
27 }
28 int main()
29 {
30     int T;
31     scanf("%d",&T);
32     while(T--)
33     {
34         scanf("%d",&n);
35         minv = INF;
36         for(int i=1;i<=n;i++) scanf("%d",&p[i]);
37         for(int i=1;i<=n;i++)
38         {
39             scanf("%d",&w[i]);
40             st[i] = 0;
41             minv = min(minv,w[i]); 
42         }
43         int res = solve();
44         printf("%d\n",res);
45     }
46     return 0;
47 }

 

posted @ 2021-04-21 21:02  acmloser  阅读(88)  评论(0编辑  收藏  举报