<링크>

https://www.acmicpc.net/problem/10972

 

<소스코드>

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[10000];
int main()
{
    int N;
    scanf("%d"&N);
    for (int i = 0; i < N; ++i)
        scanf("%d", a + i);
    int i = N - 1;
    while (i > 0 && a[i - 1> a[i])
        --i;
    if (i == 0)
    {
        printf("-1"); return 0;
    }
    int near = 10001;
    int index;
    for (int j = i; j < N; ++j)
    {
        if (a[i - 1< a[j] && a[j] < near)
        {
            near = a[j];
            index = j;
        }
    }
    int tmp = a[i - 1];
    a[i - 1= a[index];
    a[index] = tmp;
    sort(a + i, a + N);
    for (int i = 0; i < N; ++i)
        printf("%d ", a[i]);
}
cs
 

 

 

<풀이>


N이 10000이기 때문에 모든 순열을 하나하나 구해보면 N!의 시간이 걸리고 당연히 시간초과이다.그래서 하나하나 적어보며 규칙성을 찾았다.
1.

 맨 뒤에서부터 시작해서 내림차순이 끊기는 지점을 찾아낸다.

 

1 2 3 4

 

1 2 4 31 3 2 41 3 4 21 4 2 31 4 3 22 1 3 42 1 4 32 3 1 4...3 4 2 14 1 2 3...4 3 2 1

2.

 끊긴 지점에 있는 수가 증가되어야 하는데 조건이 있다. 앞에 나왔던 숫자는 제외하고, 뒤에 있는 숫자 중 크면서 가장 가까운 수로 바뀐다.

 

예를 들어보면

 

 

1이 증가되어야하는데 2로 될 수는 없다. 앞에 2가 있기 때문이다.

그럼 앞에 있는애들(2) 눈치 안보고 바뀔 수 있는 놈들은 뒤(4, 3)에 다 몰려있다.뒤에 있는 놈들 중에 누구로 바뀌면 될까 생각해봤는데 4로 바뀌면 안된다.2 1 x x 에서 바로 2 4 x x로 건너뛰는 셈이 되기 때문이다.
3으로 바뀌면2 3 x x 가 되고원래 뒤에있던 3의 자리에는 당연히 1이 들어가야한다.  즉, 맞바뀌게 된다. -> 2 3 4 1

3.

 숫자를 맞바꾸고 나면 끊긴 지점 뒤로 오름차순 정렬을 해준다.3 뒤로 오름차순정렬을 해서 2 3 1 4를 만든다.

4.

 끊긴 지점이 맨 앞이면, 맨 마지막 수열이므로 -1을 출력한다.

근데 사실 이런 고생을 안하고 풀수있는 방법이 있다. STL이 따로 있었다..

next_permutation( )

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[10000];
int main()
{
    int N;
    scanf("%d"&N);
    for (int i = 0; i<N; ++i) 
        scanf("%d", a+i);
    if(next_permutation(a, a+ N))
        for (int i = 0; i<N; i++)
            printf("%d ", a[i]);
    else printf("-1");
}
 
cs

 

<링크>

https://koitp.org/problem/SDS_TEST_CLOCK/read/


<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include<stdio.h>
int ans=0;
void check(int);
int main()
{
    int T;
    scanf("%d"&T);
    for (int t = 1; t <= T; ++t)
    {
        ans = 1439//23:59
        int a;
        int time = 0;
        for (int i = 27; i >= 0--i)
        {
            scanf("%d"&a);
            time = time | (a << i);
        }
        check(time);
        for (int i = 27; i >= 0--i)
        {
            int cVal;
            if (time & (1 << i))
                cVal = (time & ~(1 << i));
            else
                cVal = (time | 1 << i);
            check(cVal);
            for (int j = i - 1; j >= 0--j)
            {
                int dVal=cVal;
                if (dVal & (1 << j))
                    dVal = (dVal & ~(1 << j));
                else
                    dVal = (dVal | 1 << j);
                check(dVal);
            }
        }
 
        printf("#%d %d %d\n",t,ans/60, ans%60);
    }
 
}
void check(int time)
{
    int res[4= { 0, };
    for (int i = 21; i >= 0; i -= 7)
    {
        int num = -1;
        switch ((time & (0x7F << i)) >> i)
        {
        case 0x7E:num = 0break;
        case 0x06:num = 1break;
        case 0x5B:num = 2break;
        case 0x4F:num = 3break;
        case 0x27:num = 4break;
        case 0x6D:num = 5break;
        case 0x7D:num = 6break;
        case 0x46:num = 7break;
        case 0x7F:num = 8break;
        case 0x6F:num = 9break;
 
        default:return//아무숫자도 해당안하면 그건 ㅄ시계니깐 걍리턴
        }
        res[3 - i / 7= num;
    }
    int minute = res[0* 600 + res[1* 60 + res[2* 10 + res[3];
    if (minute < ans)
        ans = minute;
}
cs


<풀이>

int변수 하나에 28비트를 다 때려박은 후 쉬프트 연산을 이용해 풀었다.

각 숫자마다 정해진 7비트가 있기 때문에

16진수표시법으로 비트를 나타내었다.


이중 for문을 돌며 2개이하로 고장난 상황을 체크하였다.





<링크>

https://koitp.org/problem/SDS_TEST_BIGINT/read/


<풀이>

처음에는 덧셈횟수와 뺄셈횟수를 이용해 dfs하여 풀었으나 시간초과가 떴다. 연산자의 수가 대략 100,000개니까

100,000!이면 굉장한 시간이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<stdio.h>
int N, P, M;
int card[100000];
long long ans;
void dfs(long longint);
int main()
{
    int T;
    scanf("%d"&T);
    for (int t = 1; t <= T; ++t)
    {
        scanf("%d%d%d"&N, &P, &M);
        for (int i = 0; i < N; ++i)
            scanf("%d", card + i);
        ans = -100000000000L;
        dfs(card[0], 1);
        printf("%lld\n", ans);
    }
}
void dfs(long long n, int len)
{
    if (len == N)
    {
        if (n > ans)
            ans = n;
        return;
    }
    if (P)
    {
        --P;
        dfs(n + card[len], len + 1);
        ++P;
    }
    if (M)
    {
        --M;
        dfs(n - card[len], len + 1);
        ++M;
    }
}
cs


예전에 봤던 문제가 생각나서 나도모르게 이렇게 한 것같다.


2018/07/22 - [알고리즘 풀이/브루트 포스] - 백준 14888 연산자 끼워넣기 :: 들짐승


다시 생각해보니 덧셈은 최대한 큰 수들로만 하고

뺄셈은 최대한 작은 수들로만 하면 최대값이 나올 수 있단 걸 깨닳았다.


맨 앞의 카드만 고정시키고

뒤의 카드는 내림차순으로 정렬했다. 그 후 덧셈,뺄셈 순서대로 계산했다.


<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<stdio.h>
#include<algorithm>
#include<functional>
using namespace std;
int card[100000];
int main()
{
    int T;
    scanf("%d"&T);
    for (int t = 1; t <= T; ++t)
    {
        
        int N, P, M;
        scanf("%d%d%d"&N, &P, &M);
        for (int i = 0; i < N; ++i)
            scanf("%d", card + i);
        sort(card + 1, card + N,greater<int>());
        long long ans = card[0];
        for (int i = 1; i <= P; ++i)
            ans += card[i];
        for (int i = 1 + P; i < N; ++i)
            ans -= card[i];
        printf("#%d %lld\n", t, ans);
    }
}
cs

<링크>

https://koitp.org/problem/SDS_TEST_TREASURE/read/ 


<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
vector<int> adj[1001];
queue<int> q;
int isVisited[1001];
int N,M,K;
int bfs();
int main()
{
    int T;
    scanf("%d",&T);
    for (int t = 1; t <= T; ++t)
    {
        for (int i = 0; i <= 1000++i)
            adj[i].clear();
        q = queue<int>();
        memset(isVisited, 0sizeof(isVisited));
        scanf("%d%d%d"&N, &M, &K);
        for (int i = 0; i < M; ++i)
        {
            int a, b;
            scanf("%d%d"&a, &b);
            adj[a].push_back(b);
        }
        int ans = bfs();
        printf("#%d ", t);
        if (ans)
            printf("%d\n", ans);
        else
            printf("-1\n");
    }
    
}
int bfs()
{
    
    q.push(1);
    int depth = 0;
    while (!q.empty())
    {
        int size = q.size();
        for (int i = 0; i < size++i)
        {
            int cur = q.front();
            q.pop();
 
            if (cur == N)
                return depth;
            int s = adj[cur].size();
            for (int i = 0; i < s; ++i)
            {
                int to = adj[cur][i];
                if (!isVisited[to])
                {
                    isVisited[to] = 1;
                    q.push(to);
                }
            }
        }
        ++depth;
        if (depth > K)
            return 0;
    }
    return 0;
}
cs


<풀이>

BFS를 통해 목적지가 나오면 그 때의 depth가 답이다.

또한 depth가 K를 초과하면 더이상 탐색할 필요가 없고

모든 노드를 다 돌아봤음에도 목적지를 못찾으면 답은 -1이다.



'알고리즘 풀이 > BFS' 카테고리의 다른 글

백준 2251 물통  (0) 2018.08.01
백준 1525 퍼즐  (0) 2018.07.31
백준 9019 DSLR  (0) 2018.07.31
백준 1963 소수 경로  (2) 2018.07.30
백준 1697 숨바꼭질  (1) 2018.07.29

<링크>

https://www.acmicpc.net/problem/11724


<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Scanner;
 
public class Main {
    static int N,M;
    static ArrayList<Integer> adj[]=new ArrayList[1001];
    static boolean isVisited[]=new boolean[1001];
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        for(int i=1;i<=1000;++i)
            adj[i]=new ArrayList<Integer>();
        
        N=in.nextInt();
        M=in.nextInt();
        for(int i=0;i<M;++i) {
            int a=in.nextInt();
            int b=in.nextInt();
            adj[a].add(b);
            adj[b].add(a);
        }
        int ans=0;
        for(int i=1;i<=N;++i) {
            if(!isVisited[i]) {
                isVisited[i]=true;
                ++ans;
                dfs(i);
                
            }
        }
        System.out.println(ans);
    }
    static void dfs(int i) {
        int len=adj[i].size();
        for(int k=0;k<len;++k)
        {
            int toi=adj[i].get(k);
            if(!isVisited[toi]) {
                isVisited[toi]=true;
                dfs(toi);
            }
        }
    }
}
 
cs


<풀이>

1. for문을 돌면서 모든 노드를 시작점으로 dfs를 한다.

2. 한 번 방문했던 노드는 다시 보지 않는다. 시작점 노드도 예외는 없다.

3. dfs를 총 몇 번 했는지 세어주면 답이 나온다.




'알고리즘 풀이 > DFS' 카테고리의 다른 글

백준 10819 차이를 최대로  (0) 2018.07.27
백준 10974 모든 순열  (2) 2018.07.24
KOITP 큰수만들기  (0) 2018.07.23
백준 11403 경로 찾기 :: 들짐승  (0) 2018.07.23
백준 1240 노드사이의 거리 ::들짐승  (0) 2018.07.22

+ Recent posts